]> git.saurik.com Git - apple/ld64.git/commitdiff
ld64-123.2.tar.gz developer-tools-40 v123.2
authorApple <opensource@apple.com>
Fri, 10 Dec 2010 22:41:27 +0000 (22:41 +0000)
committerApple <opensource@apple.com>
Fri, 10 Dec 2010 22:41:27 +0000 (22:41 +0000)
317 files changed:
ChangeLog
doc/man/man1/dyldinfo.1
doc/man/man1/ld.1
ld64.xcodeproj/project.pbxproj
src/abstraction/FileAbstraction.hpp
src/abstraction/MachOFileAbstraction.hpp
src/abstraction/MachOTrie.hpp
src/ld/Architectures.hpp
src/ld/ArchiveReader.hpp [deleted file]
src/ld/ExecutableFile.h [deleted file]
src/ld/HeaderAndLoadCommands.hpp [new file with mode: 0644]
src/ld/InputFiles.cpp [new file with mode: 0644]
src/ld/InputFiles.h [new file with mode: 0644]
src/ld/LTOReader.hpp [deleted file]
src/ld/LinkEdit.hpp [new file with mode: 0644]
src/ld/LinkEditClassic.hpp [new file with mode: 0644]
src/ld/MachOReaderDylib.hpp [deleted file]
src/ld/MachOReaderRelocatable.hpp [deleted file]
src/ld/MachOWriterExecutable.hpp [deleted file]
src/ld/ObjectFile.h [deleted file]
src/ld/OpaqueSection.hpp [deleted file]
src/ld/Options.cpp
src/ld/Options.h
src/ld/OutputFile.cpp [new file with mode: 0644]
src/ld/OutputFile.h [new file with mode: 0644]
src/ld/Resolver.cpp [new file with mode: 0644]
src/ld/Resolver.h [new file with mode: 0644]
src/ld/SectCreate.h [deleted file]
src/ld/SymbolTable.cpp [new file with mode: 0644]
src/ld/SymbolTable.h [new file with mode: 0644]
src/ld/debugline.c
src/ld/debugline.h
src/ld/ld.cpp
src/ld/ld.hpp [new file with mode: 0644]
src/ld/lto_file.hpp [new file with mode: 0644]
src/ld/parsers/archive_file.cpp [new file with mode: 0644]
src/ld/parsers/archive_file.h [new file with mode: 0644]
src/ld/parsers/lto_file.cpp [new file with mode: 0644]
src/ld/parsers/lto_file.h [new file with mode: 0644]
src/ld/parsers/macho_dylib_file.cpp [new file with mode: 0644]
src/ld/parsers/macho_dylib_file.h [new file with mode: 0644]
src/ld/parsers/macho_relocatable_file.cpp [new file with mode: 0644]
src/ld/parsers/macho_relocatable_file.h [new file with mode: 0644]
src/ld/parsers/opaque_section_file.cpp [new file with mode: 0644]
src/ld/parsers/opaque_section_file.h [new file with mode: 0644]
src/ld/passes/branch_island.cpp [new file with mode: 0644]
src/ld/passes/branch_island.h [new file with mode: 0644]
src/ld/passes/branch_shim.cpp [new file with mode: 0644]
src/ld/passes/branch_shim.h [new file with mode: 0644]
src/ld/passes/compact_unwind.cpp [new file with mode: 0644]
src/ld/passes/compact_unwind.h [new file with mode: 0644]
src/ld/passes/dtrace_dof.cpp [new file with mode: 0644]
src/ld/passes/dtrace_dof.h [new file with mode: 0644]
src/ld/passes/dylibs.cpp [new file with mode: 0644]
src/ld/passes/dylibs.h [new file with mode: 0644]
src/ld/passes/got.cpp [new file with mode: 0644]
src/ld/passes/got.h [new file with mode: 0644]
src/ld/passes/huge.cpp [new file with mode: 0644]
src/ld/passes/huge.h [new file with mode: 0644]
src/ld/passes/objc.cpp [new file with mode: 0644]
src/ld/passes/objc.h [new file with mode: 0644]
src/ld/passes/order_file.cpp [new file with mode: 0644]
src/ld/passes/order_file.h [new file with mode: 0644]
src/ld/passes/stubs/make_stubs.h [new file with mode: 0644]
src/ld/passes/stubs/stub_arm.hpp [new file with mode: 0644]
src/ld/passes/stubs/stub_arm_classic.hpp [new file with mode: 0644]
src/ld/passes/stubs/stub_ppc_classic.hpp [new file with mode: 0644]
src/ld/passes/stubs/stub_x86.hpp [new file with mode: 0644]
src/ld/passes/stubs/stub_x86_64.hpp [new file with mode: 0644]
src/ld/passes/stubs/stub_x86_64_classic.hpp [new file with mode: 0644]
src/ld/passes/stubs/stub_x86_classic.hpp [new file with mode: 0644]
src/ld/passes/stubs/stubs.cpp [new file with mode: 0644]
src/ld/passes/tlvp.cpp [new file with mode: 0644]
src/ld/passes/tlvp.h [new file with mode: 0644]
src/other/ObjectDump.cpp
src/other/dyldinfo.cpp
src/other/machochecker.cpp
src/other/rebase.cpp
src/other/unwinddump.cpp
unit-tests/bin/result-filter.pl
unit-tests/include/common.makefile
unit-tests/run-all-unit-tests
unit-tests/test-cases/16-byte-alignment/Makefile
unit-tests/test-cases/Lpath/Makefile [new file with mode: 0644]
unit-tests/test-cases/Lpath/foo.c [new file with mode: 0644]
unit-tests/test-cases/Lpath/main.c [new file with mode: 0644]
unit-tests/test-cases/absolute-symbol/abs.s
unit-tests/test-cases/alias-command-line/Makefile
unit-tests/test-cases/alias-command-line/aliases.s
unit-tests/test-cases/alias-command-line/aliases.txt
unit-tests/test-cases/allow_heap_execute/Makefile [new file with mode: 0644]
unit-tests/test-cases/allow_heap_execute/main.c [new file with mode: 0644]
unit-tests/test-cases/archive-ObjC-unexported/Makefile [new file with mode: 0644]
unit-tests/test-cases/archive-ObjC-unexported/bar.m [new file with mode: 0644]
unit-tests/test-cases/archive-ObjC-unexported/foo.m [new file with mode: 0644]
unit-tests/test-cases/archive-ObjC-unexported/main.m [new file with mode: 0644]
unit-tests/test-cases/archive-ObjC-unexported/main.nexp [new file with mode: 0644]
unit-tests/test-cases/archive-image_info/Makefile [new file with mode: 0644]
unit-tests/test-cases/archive-image_info/main.m [new file with mode: 0644]
unit-tests/test-cases/bind_at_load/Makefile [new file with mode: 0644]
unit-tests/test-cases/bind_at_load/bar.c [new file with mode: 0644]
unit-tests/test-cases/bind_at_load/foo.c [new file with mode: 0644]
unit-tests/test-cases/bind_at_load/main.c [new file with mode: 0644]
unit-tests/test-cases/blank-stubs/Makefile
unit-tests/test-cases/branch-distance/Makefile
unit-tests/test-cases/branch-interworking/Makefile [new file with mode: 0644]
unit-tests/test-cases/branch-interworking/myarm.s [new file with mode: 0644]
unit-tests/test-cases/branch-interworking/mythumb.s [new file with mode: 0644]
unit-tests/test-cases/cfstring-and-cstring/Makefile [new file with mode: 0644]
unit-tests/test-cases/cfstring-and-cstring/bar.c [new file with mode: 0644]
unit-tests/test-cases/cfstring-and-cstring/foo.c [new file with mode: 0644]
unit-tests/test-cases/cfstring-utf16/Makefile
unit-tests/test-cases/coalesce_weak_def_in_dylib/Makefile
unit-tests/test-cases/commons-order/Makefile
unit-tests/test-cases/cstring-alt-segment/Makefile
unit-tests/test-cases/cstring-alt-segment/custom.s
unit-tests/test-cases/cstring-empty-labeled/Makefile [new file with mode: 0644]
unit-tests/test-cases/cstring-empty-labeled/foo.s [new file with mode: 0644]
unit-tests/test-cases/custom-segment-layout/Makefile [new file with mode: 0644]
unit-tests/test-cases/custom-segment-layout/main.c [new file with mode: 0644]
unit-tests/test-cases/custom-segment-layout/zero.s [new file with mode: 0644]
unit-tests/test-cases/dead_strip-archive-duplicate-def/Makefile [new file with mode: 0644]
unit-tests/test-cases/dead_strip-archive-duplicate-def/bar.c [new file with mode: 0644]
unit-tests/test-cases/dead_strip-archive-duplicate-def/foo.c [new file with mode: 0644]
unit-tests/test-cases/dead_strip-archive-duplicate-def/main.c [new file with mode: 0644]
unit-tests/test-cases/dead_strip-archive-weak-override/Makefile [new file with mode: 0644]
unit-tests/test-cases/dead_strip-archive-weak-override/bar.c [new file with mode: 0644]
unit-tests/test-cases/dead_strip-archive-weak-override/foo.c [new file with mode: 0644]
unit-tests/test-cases/dead_strip-archive-weak-override/main.c [new file with mode: 0644]
unit-tests/test-cases/dead_strip/Makefile
unit-tests/test-cases/demangle/Makefile [new file with mode: 0644]
unit-tests/test-cases/demangle/main.cxx [new file with mode: 0644]
unit-tests/test-cases/dependency-logging/Makefile [new file with mode: 0644]
unit-tests/test-cases/dependency-logging/foo.c [new file with mode: 0644]
unit-tests/test-cases/dependency-logging/main.c [new file with mode: 0644]
unit-tests/test-cases/dtrace-old-probes/Makefile [new file with mode: 0644]
unit-tests/test-cases/dtrace-old-probes/main.c [new file with mode: 0644]
unit-tests/test-cases/dtrace-static-probes-coalescing/x.cxx
unit-tests/test-cases/dtrace-static-probes/Makefile
unit-tests/test-cases/dwarf-debug-notes-r/Makefile
unit-tests/test-cases/dwarf-debug-notes-uuid/Makefile [new file with mode: 0644]
unit-tests/test-cases/dwarf-debug-notes-uuid/main.c [new file with mode: 0644]
unit-tests/test-cases/dwarf-debug-notes/Makefile
unit-tests/test-cases/dwarf-debug-notes/expected-stabs
unit-tests/test-cases/dwarf-strip-objc/Makefile [new file with mode: 0644]
unit-tests/test-cases/dwarf-strip-objc/hello.m [new file with mode: 0644]
unit-tests/test-cases/dwarf-strip/Makefile
unit-tests/test-cases/dylib-aliases/Makefile
unit-tests/test-cases/dylib-re-export-cycle/Makefile
unit-tests/test-cases/dylib-upward/Makefile [new file with mode: 0644]
unit-tests/test-cases/dylib-upward/bar.c [new file with mode: 0644]
unit-tests/test-cases/dylib-upward/foo.c [new file with mode: 0644]
unit-tests/test-cases/efi-basic/LibTest.c [new file with mode: 0644]
unit-tests/test-cases/efi-basic/Makefile [new file with mode: 0644]
unit-tests/test-cases/efi-basic/MtocTest.c [new file with mode: 0644]
unit-tests/test-cases/efi-basic/mtoctest.py [new file with mode: 0755]
unit-tests/test-cases/eh-coalescing/bar.cxx
unit-tests/test-cases/eh-stripped-symbols/Makefile
unit-tests/test-cases/eh-stripped-symbols/main.cxx
unit-tests/test-cases/empty-dylib/Makefile
unit-tests/test-cases/exported-symbols-dead_strip/Makefile [new file with mode: 0644]
unit-tests/test-cases/exported-symbols-dead_strip/foo.c [new file with mode: 0644]
unit-tests/test-cases/exported-symbols-dead_strip/foo.exp [new file with mode: 0644]
unit-tests/test-cases/function-starts/Makefile [new file with mode: 0644]
unit-tests/test-cases/function-starts/main.c [new file with mode: 0644]
unit-tests/test-cases/hidden-r/Makefile [new file with mode: 0644]
unit-tests/test-cases/hidden-r/foo.c [new file with mode: 0644]
unit-tests/test-cases/hidden-r/main.c [new file with mode: 0644]
unit-tests/test-cases/kext-basic/mykext.c
unit-tests/test-cases/label-on-end-of-section/Makefile
unit-tests/test-cases/large-bss/Makefile [new file with mode: 0644]
unit-tests/test-cases/large-bss/test.s [new file with mode: 0644]
unit-tests/test-cases/lazy-dylib-objc/Makefile
unit-tests/test-cases/lazy-dylib/Makefile
unit-tests/test-cases/literals-labels/Makefile [new file with mode: 0644]
unit-tests/test-cases/literals-labels/literals.s [new file with mode: 0644]
unit-tests/test-cases/llvm-integration/Makefile
unit-tests/test-cases/llvm-integration/a17.c
unit-tests/test-cases/lto-dead_strip-objc/Makefile [new file with mode: 0644]
unit-tests/test-cases/lto-dead_strip-objc/foo.m [new file with mode: 0644]
unit-tests/test-cases/lto-dead_strip-some-hidden/Makefile [new file with mode: 0644]
unit-tests/test-cases/lto-dead_strip-some-hidden/bar.c [new file with mode: 0644]
unit-tests/test-cases/lto-dead_strip-tentative/Makefile [new file with mode: 0644]
unit-tests/test-cases/lto-dead_strip-tentative/bar.c [new file with mode: 0644]
unit-tests/test-cases/lto-dead_strip-tentative/baz.c [new file with mode: 0644]
unit-tests/test-cases/lto-dead_strip-tentative/foo.c [new file with mode: 0644]
unit-tests/test-cases/lto-dead_strip-tentative/main.c [new file with mode: 0644]
unit-tests/test-cases/lto-dead_strip-unused/Makefile [new file with mode: 0644]
unit-tests/test-cases/lto-dead_strip-unused/bar.c [new file with mode: 0644]
unit-tests/test-cases/lto-dead_strip-unused/main.c [new file with mode: 0644]
unit-tests/test-cases/lto-objc-image-info/Makefile [new file with mode: 0644]
unit-tests/test-cases/lto-objc-image-info/main.m [new file with mode: 0644]
unit-tests/test-cases/lto-object_path/Makefile [new file with mode: 0644]
unit-tests/test-cases/lto-object_path/main.c [new file with mode: 0644]
unit-tests/test-cases/main-stripped/Makefile
unit-tests/test-cases/main-stripped/main.c
unit-tests/test-cases/main-stripped/main.exp
unit-tests/test-cases/no-uuid/Makefile
unit-tests/test-cases/non-lazy-r/Makefile
unit-tests/test-cases/non-lazy-r/foo.c
unit-tests/test-cases/non-lazy-r/other.c
unit-tests/test-cases/non-lazy-sections-r/Makefile [new file with mode: 0644]
unit-tests/test-cases/non-lazy-sections-r/foo.s [new file with mode: 0644]
unit-tests/test-cases/objc-abi/Makefile [new file with mode: 0644]
unit-tests/test-cases/objc-abi/test.m [new file with mode: 0644]
unit-tests/test-cases/objc-category-archive/Makefile [new file with mode: 0644]
unit-tests/test-cases/objc-category-archive/main.m [new file with mode: 0644]
unit-tests/test-cases/objc-category-archive/test.m [new file with mode: 0644]
unit-tests/test-cases/objc-category-optimize-load/Makefile [new file with mode: 0644]
unit-tests/test-cases/objc-category-optimize-load/cat1.m [new file with mode: 0644]
unit-tests/test-cases/objc-category-optimize-load/foo.m [new file with mode: 0644]
unit-tests/test-cases/objc-category-optimize/Makefile [new file with mode: 0644]
unit-tests/test-cases/objc-category-optimize/cat1.m [new file with mode: 0644]
unit-tests/test-cases/objc-category-optimize/cat2.m [new file with mode: 0644]
unit-tests/test-cases/objc-category-optimize/foo.m [new file with mode: 0644]
unit-tests/test-cases/objc-class-alias/Makefile [new file with mode: 0644]
unit-tests/test-cases/objc-class-alias/test.m [new file with mode: 0644]
unit-tests/test-cases/objc-gc-checks/Makefile
unit-tests/test-cases/objc-gc-checks/none.c [new file with mode: 0644]
unit-tests/test-cases/objc-literal-pointers/Makefile
unit-tests/test-cases/objc-properties/Makefile [new file with mode: 0644]
unit-tests/test-cases/objc-properties/test.m [new file with mode: 0644]
unit-tests/test-cases/objc-visibility/Makefile [new file with mode: 0644]
unit-tests/test-cases/objc-visibility/bar.h [new file with mode: 0644]
unit-tests/test-cases/objc-visibility/bar.m [new file with mode: 0644]
unit-tests/test-cases/objc-visibility/foo.h [new file with mode: 0644]
unit-tests/test-cases/objc-visibility/foo.m [new file with mode: 0644]
unit-tests/test-cases/order_file-ans/main.cxx
unit-tests/test-cases/order_file/Makefile
unit-tests/test-cases/order_file/extra.s
unit-tests/test-cases/order_file/main4.expected [new file with mode: 0644]
unit-tests/test-cases/order_file/main4.order [new file with mode: 0644]
unit-tests/test-cases/re-export-and-use/Makefile [new file with mode: 0644]
unit-tests/test-cases/re-export-and-use/bar.c [new file with mode: 0644]
unit-tests/test-cases/re-export-and-use/baz.c [new file with mode: 0644]
unit-tests/test-cases/re-export-and-use/foo.c [new file with mode: 0644]
unit-tests/test-cases/re-export-and-use/pub.c [new file with mode: 0644]
unit-tests/test-cases/re-export-layers/Makefile [new file with mode: 0644]
unit-tests/test-cases/re-export-layers/bar.c [new file with mode: 0644]
unit-tests/test-cases/re-export-layers/baz.c [new file with mode: 0644]
unit-tests/test-cases/re-export-layers/foo.c [new file with mode: 0644]
unit-tests/test-cases/re-export-layers/main.c [new file with mode: 0644]
unit-tests/test-cases/re-export-symbol/Makefile [new file with mode: 0644]
unit-tests/test-cases/re-export-symbol/bar.c [new file with mode: 0644]
unit-tests/test-cases/re-export-symbol/foo.c [new file with mode: 0644]
unit-tests/test-cases/re-export-symbol/foo.exp [new file with mode: 0644]
unit-tests/test-cases/re-export-symbol/foo2.exp [new file with mode: 0644]
unit-tests/test-cases/re-export-symbol/main1.c [new file with mode: 0644]
unit-tests/test-cases/re-export-symbol/main2.c [new file with mode: 0644]
unit-tests/test-cases/read-only-relocs/Makefile
unit-tests/test-cases/read-only-relocs/main.c [new file with mode: 0644]
unit-tests/test-cases/read-only-relocs/test_bind.c [new file with mode: 0644]
unit-tests/test-cases/read-only-relocs/test_rebase.c [new file with mode: 0644]
unit-tests/test-cases/rebase-basic/Makefile
unit-tests/test-cases/reexport_symbols_list/Makefile [new file with mode: 0644]
unit-tests/test-cases/reexport_symbols_list/bar.c [new file with mode: 0644]
unit-tests/test-cases/reexport_symbols_list/bart.exp [new file with mode: 0644]
unit-tests/test-cases/reexport_symbols_list/foo.c [new file with mode: 0644]
unit-tests/test-cases/reexport_symbols_list/foo.exp [new file with mode: 0644]
unit-tests/test-cases/reexport_symbols_list/junk.exp [new file with mode: 0644]
unit-tests/test-cases/reexport_symbols_list/main1.c [new file with mode: 0644]
unit-tests/test-cases/relocs-asm/relocs-asm.s
unit-tests/test-cases/relocs-neg-from-local/Makefile
unit-tests/test-cases/sectcreate-dead_strip/Makefile [new file with mode: 0644]
unit-tests/test-cases/sectcreate-dead_strip/main.c [new file with mode: 0644]
unit-tests/test-cases/sectcreate-dead_strip/sect_content [new file with mode: 0644]
unit-tests/test-cases/segment-labels/Makefile [new file with mode: 0644]
unit-tests/test-cases/segment-labels/main.c [new file with mode: 0644]
unit-tests/test-cases/segment-labels/test.c [new file with mode: 0644]
unit-tests/test-cases/stabs-coalesce/Makefile
unit-tests/test-cases/static-executable-weak-defines/Makefile
unit-tests/test-cases/static-executable-weak-defines/test.c
unit-tests/test-cases/static-executable/test.c
unit-tests/test-cases/symbol-hiding-umbrella/Makefile [new file with mode: 0644]
unit-tests/test-cases/symbol-hiding-umbrella/bar.c [new file with mode: 0644]
unit-tests/test-cases/symbol-hiding-umbrella/foo.c [new file with mode: 0644]
unit-tests/test-cases/symbol-hiding-umbrella/main.c [new file with mode: 0644]
unit-tests/test-cases/symbol-resolver-basic/Makefile [new file with mode: 0644]
unit-tests/test-cases/symbol-resolver-basic/foo.c [new file with mode: 0644]
unit-tests/test-cases/symbol-resolver-hidden/Makefile [new file with mode: 0644]
unit-tests/test-cases/symbol-resolver-hidden/foo.c [new file with mode: 0644]
unit-tests/test-cases/tentative-to-real-r/Makefile
unit-tests/test-cases/tlv-basic/Makefile [new file with mode: 0644]
unit-tests/test-cases/tlv-basic/get.s [new file with mode: 0644]
unit-tests/test-cases/tlv-basic/main.c [new file with mode: 0644]
unit-tests/test-cases/tlv-dylib/Makefile [new file with mode: 0644]
unit-tests/test-cases/tlv-dylib/foo.s [new file with mode: 0644]
unit-tests/test-cases/tlv-dylib/getbar.s [new file with mode: 0644]
unit-tests/test-cases/tlv-dylib/getfoo.s [new file with mode: 0644]
unit-tests/test-cases/tlv-dylib/main.c [new file with mode: 0644]
unit-tests/test-cases/umbrella-dylib/Makefile [new file with mode: 0644]
unit-tests/test-cases/umbrella-dylib/a.c [new file with mode: 0644]
unit-tests/test-cases/umbrella-dylib/b.c [new file with mode: 0644]
unit-tests/test-cases/umbrella-dylib/c.c [new file with mode: 0644]
unit-tests/test-cases/umbrella-dylib/main.c [new file with mode: 0644]
unit-tests/test-cases/undefined-dynamic-lookup/Makefile
unit-tests/test-cases/unstrippable-symbols/Makefile [new file with mode: 0644]
unit-tests/test-cases/unstrippable-symbols/foo.c [new file with mode: 0644]
unit-tests/test-cases/utf16-nul/Makefile [new file with mode: 0644]
unit-tests/test-cases/utf16-nul/other.s [new file with mode: 0644]
unit-tests/test-cases/utf16-nul/withnul.s [new file with mode: 0644]
unit-tests/test-cases/visibility-warning/Makefile
unit-tests/test-cases/weak-def-auto-hide/Makefile [new file with mode: 0644]
unit-tests/test-cases/weak-def-auto-hide/main.c [new file with mode: 0644]
unit-tests/test-cases/weak-def-auto-hide/other.s [new file with mode: 0644]
unit-tests/test-cases/weak-def-flag/Makefile
unit-tests/test-cases/weak-force/Makefile [new file with mode: 0644]
unit-tests/test-cases/weak-force/foo.c [new file with mode: 0644]
unit-tests/test-cases/weak-force/foo1.exp [new file with mode: 0644]
unit-tests/test-cases/weak-force/foo2.exp [new file with mode: 0644]
unit-tests/test-cases/weak_import-force/main.c
unit-tests/test-cases/weak_import-local/Makefile [new file with mode: 0644]
unit-tests/test-cases/weak_import-local/foo.c [new file with mode: 0644]
unit-tests/test-cases/weak_import-local/foo.h [new file with mode: 0644]
unit-tests/test-cases/weak_import-local/main.c [new file with mode: 0644]
unit-tests/test-cases/weak_import/main.c
unit-tests/test-cases/zero-fill2/test.c

index ebd56281d8bb21d0ce679cdd5b71050329887fdb..bc918bbce17928fea67b5757b899ef9ccc703f6f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
 
------ Tagged ld64-97.17
+2010-12-10    Nick Kledzik    <kledzik@apple.com>
 
-2010-09-07    Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/8746980> Man page typo: "dysmutil" under object_path_lto
 
-       <rdar://problem/7989734> ld mis-handling std::tr1::anonymous symbols
-       Remove support for ordering gcc-4.0 compiled anonymous namespace symbols
+2010-12-10    Nick Kledzik    <kledzik@apple.com>
+       
+       <rdar://problem/8746896> ld64 crashes when warning about re-exported symbol
 
-2010-09-07    Nick Kledzik    <kledzik@apple.com>
+-------- tagged ld64-123.1
 
-       <rdar://problem/8388362> RedGarnet's linker does not honor $ld$hide for umbrella libraries
+2010-12-07    Nick Kledzik    <kledzik@apple.com>
 
------ Tagged ld64-97.16
+       <rdar://problem/8732097> assertion if symbol from re-exported dylib is in -exported_symbols_list
 
-2010-08-10    Nick Kledzik    <kledzik@apple.com>
+-------- tagged ld64-123
 
-       <rdar://problem/8303976> add -demangle noop to ld64-97
+2010-12-06    Nick Kledzik    <kledzik@apple.com>
 
------ Tagged ld64-97.15
+       <rdar://problem/8649182> Change default search order and add -search_dylibs_first to restore old behavior
 
-2010-08-10    Nick Kledzik    <kledzik@apple.com>
+2010-12-06    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/8212744> linker crash when using LTO in lto::Atom::getSymbolTableInclusion()
+       <rdar://problem/8626058> ld should consistently warn when resolvers are not exported
 
------ Tagged ld64-97.14
+2010-12-02    Nick Kledzik    <kledzik@apple.com>
 
-2010-04-20    Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/8723307> data segment has file offset 0
 
-       <rdar://problem/7712869> if last section is zero-fill don't add size to filesize total in -r mode
+-------- tagged ld64-122
 
------ Tagged ld64-97.13
+2010-12-01    Nick Kledzik    <kledzik@apple.com>
 
-2010-03-17    Nick Kledzik    <kledzik@apple.com>
+       Add #define ARM_RELOC_HALF in case trying to build with old mach-o/arm/reloc.h header
 
-       <rdar://problem/7824112> Support for iPhoneSimulator with OBJC 2.0 ABI
+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
 
------ Tagged ld64-97.12
+2010-11-30    Nick Kledzik    <kledzik@apple.com>
 
-2010-03-17    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
 
-       <rdar://problem/7712869> if last section is zero-fill don't add size to filesize total in -r mode
+-------- tagged ld64-121
 
------ Tagged ld64-97.11
+2010-11-10    Nick Kledzik    <kledzik@apple.com>
 
-2010-01-26    Nick Kledzik    <kledzik@apple.com>
+       Add -dylibs option to dyldinfo tool
 
-       <rdar://problem/7622634> Libc-624.1 causes latent ld bug
-       * build linker -no_pie
-       
+2010-11-03    Nick Kledzik    <kledzik@apple.com>
 
------ Tagged ld64-97.10
+       <rdar://problem/7441442> Need support for ARM/thumb upper/lower 16 bit relocation
 
-2010-01-26    Nick Kledzik    <kledzik@apple.com>
-       
-       <rdar://problem/7556912> LC_SEGMENT command 0 filesize field greater than vmsize field
-       * Move __DATA to end in -r mode
-       
+2010-11-03    Nick Kledzik    <kledzik@apple.com>
 
-2010-01-26    Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/8624334> Spelling typo in linker warning 
 
-       <rdar://problem/7516793> symboled __ustring strings of just 0x0000 mis-parsed
-       * Parse __ustring section based on content - not just labels
+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
 
------ Tagged ld64-97.9
+2010-11-01    Nick Kledzik    <kledzik@apple.com>
 
-2010-01-14    Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/8618747> ld wrongly complaining about tlv relocs for i386
 
-       <rdar://problem/7532743> LC_SEGMENT command 0 filesize field greater than vmsize field
-       * for i386 -r mode sort __IMPORT segment before __DATA segment
+2010-11-01    Nick Kledzik    <kledzik@apple.com>
 
+       Fix -why_live to list all references, not just first
 
-2010-01-11    Nick Kledzik    <kledzik@apple.com>
+2010-11-01    Nick Kledzik    <kledzik@apple.com>
 
-       * fix ARM -r -d references to tentative definitions
+       <rdar://problem/8612861> Durango is missing dof sections for armv7 slice
 
------ Tagged ld64-97.8
+-------- tagged ld64-120.3
 
-2009-12-08    Nick Kledzik    <kledzik@apple.com>
+2010-11-09    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/7455147> many mach-o images in Barolo have MH_WEAK_DEFINES bit incorrectly set
-       * don't let auto-strip weak symbols set MH_WEAK_DEFINES
+       <rdar://problem/8644314> revert default search order 
        
+-------- tagged ld64-120.2
 
------ Tagged ld64-97.7
-
-2009-11-30    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/7429384> llvmgcc now puts const short arrays in __ustring section, linker does not handle that
-       * Only auto-coalesce UTF16 strings that are labeled with "___utf16_string*"
-
-
------ Tagged ld64-97.6
-2009-11-06    Nick Kledzik    <kledzik@apple.com>
-       <rdar://problem/7332627> make -pie default for x86_64 for 10.7 and later
-
-
-2009-10-28    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/7331635> Add a -no_pie flag
-       * support -no_pie and LD_NO_PIE
-
+2010-11-09    Nick Kledzik    <kledzik@apple.com>
 
------ Tagged ld64-97.5
+       <rdar://problem/8510696> ld -r corrupts multiple non-lazy sections
 
-2009-10-27     Nick Kledzik    <kledzik@apple.com>
+-------- tagged ld64-120.1
 
-       <rdar://problem/7341117> crash when __ustring section has zero length string
-       * stop trying to suppress tailing 0x0000 from synthesized string used to coalese utf16 strings
+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-97.4
-
-2009-10-21     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/7320293> missing thumb bit when thumb function takes address of itself
-       * move toao.atom == srcao.atom test to after fromao.atom == srcao.atom test
-       
-
------ Tagged ld64-97.3
-
-2009-10-06     Nick Kledzik    <kledzik@apple.com>
-
-       * Add missing LittleEndian::set32() in arm::kPointerDiff
-
-2009-10-05     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/7268427> ARM: handle pointer-diff to weak thumb that is overridden by non-weak ARM
-       * When parsing ARM relocations, if target is a thumb function, remove one from addend
-       * When writing out content for arm::kPointerDiff, add one if target is thumb
-       * When writing ARM_RELOC_SECTDIFF, use target offsets if they fit in function
-
-
------ Tagged ld64-97.2
-
-2009-09-25     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/7200658> 'unknown DWARF EH encoding' message logged to console with clang-50
-
-
------ Tagged ld64-97.1
-
-2009-07-28     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/7099040> make better no-PIC branch island to thumb1
-       * Add kBranchIslandNoPicToThumb1 as 8-byte no-PIC island
+-------- tagged ld64-120
 
+2010-10-25    Nick Kledzik    <kledzik@apple.com>
 
-2009-07-20     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
 
-       <rdar://problem/7075703> section$start$__DATA$__bss can fail
-       * In SectionBoundaryAtom constructor make __bss and __common be zero-fill
-       * In AtomSorter, make sure end kSectionEnd sort after kTentativeDefinition
-       * unit-tests/test-cases/section-labels-zero-fill: add test cases
+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
 
------ Tagged ld64-97
+2010-10-25    Nick Kledzik    <kledzik@apple.com>
 
-2009-07-13     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/7049478> empty dylib should have subtype from command line
-       In Linker::writeOutput() for ARM, set initial fCurrentCpuConstraint to be command line subtype
-
-
-2009-07-09     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/7043920> crash when using -dead_strip and LTO with unresolved intrinsic
-       * In Linker::optimize() after final deadStripResolve() call checkUndefines() one last time
-
-
-2009-07-09     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/7043256> ld64 can not find a -e entry point from an archive
-       * src/ld/ld.cpp: add searchArchives parameter to entryPoint() for use by deadStripResolve()
-       * unit-tests/test-cases/dead_strip-entry-archive: added test case
+       Always print arch name on undefined symbols error
        
+2010-10-25    Nick Kledzik    <kledzik@apple.com>
 
-2009-07-08     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/6702217> __objc_classrefs section could be coalesced
-       * In machoReader, chop up __objc_classrefs section into pointer size atoms
-       and make each weak and hidden with a name based on its target name. 
+       Add ld64 version number to crash logs
        
+2010-10-22    Nick Kledzik    <kledzik@apple.com>
 
-2009-06-26     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/7952947> -objc_abi_version 1 not supported
 
-       <rdar://problem/6715874> "ld: symbol dyld_stub_binding_helper not defined" for xnu built with clang for x86_64
-       * Fix relocationNeededInFinalLinkedImage() to say weak-defs don't require indirection in static executables
-       * Added unit-tests/test-cases/static-executable-weak-defines
+2010-10-22    Nick Kledzik    <kledzik@apple.com>
 
+       <rdar://problem/5591394> Add support to ld64 for N_FUN stabs when used for symbolic constants
 
-2009-06-26     Nick Kledzik    <kledzik@apple.com>
+2010-10-22    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/7012016> Error msg for missing -init symbol is misleading/unclear
-       * In Linker::checkUndefines() check all ways that the command line could add an undefined
-         and then search for close matches/typos.
+       <rdar://problem/3560832> Change default search order and add -search_dylibs_first to restore old behavior
 
+2010-10-22    Nick Kledzik    <kledzik@apple.com>
 
-2009-06-25     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5725900> We need ld-symbol-moving-symbols for ARM/Embedded
-       * In mach_o::dylib::Reader::addSymbol() parse iPhoneOS version strings
-       * Update IPhoneVersionMin
-       
-
-2009-06-25     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/6933931> Linker makes subtype-zero file from empty subtype-nonzero file.
-       * In Linker::writeOutput() set inittal fCurrentCpuConstraint to be command line subtype
-       * Fix fArchitectureName to have arm sub-types
+       <rdar://problem/6955037> -L flag should support a space between it and its argument
 
+2010-10-22    Nick Kledzik    <kledzik@apple.com>
 
-2009-06-24     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/8553647> Hidden resolver functions don't work with DYLD_BIND_AT_LAUNCH
 
-       <rdar://problem/6955021> ld should do a better job of reporting attempts to link directories
-       * In Options::buildSearchPaths() sanity check -L and -F options
-       
+2010-10-22    Nick Kledzik    <kledzik@apple.com>
 
-2009-06-24     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/8541707> Support resolver functions for function pointer use from same linkage unit
 
-       <rdar://problem/6974647> better error message when libLTO.dylib not loadable
-       * in Linker::createReader() provide detail error messages
+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-96.10
+-------- tagged ld64-119.2
 
-2009-08-31     Nick Kledzik    <kledzik@apple.com>
+2010-10-18    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/7182988> empty dylib has been __mh_dylib_header n_sect
-       * rework patch to use MinimalTextAtom to ensure there is always a __text section 
-       
+       <rdar://problem/8553312> make having an ObjC2 class symbol in an export list be a warning instead of an error
 
------ Tagged ld64-96.9
+2010-10-15    Nick Kledzik    <kledzik@apple.com>
 
-2009-08-31     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/8553283> lazily produce (crt1.o missing) error
 
-       <rdar://problem/7182988> empty dylib has been __mh_dylib_header n_sect
-       * suppress __mh_dylib_header from symbol table if there is no __text section
-       
-       Implicitly add dyld_stub_binder to libSystem.dylib so iPhone clients can build
-       against SnowLeopard libSystem.dylib.
+-------- tagged ld64-119.1
 
+2010-10-05    Nick Kledzik    <kledzik@apple.com>
 
------ Tagged ld64-96.8
+       <rdar://problem/8527740> ld -r can produce output with LC_DYLD_INFO load command
 
-2009-08-30     Nick Kledzik    <kledzik@apple.com>
+2010-10-05    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/7049478> SWB: gcc-5577.1 fails to build vecLib
-               
+       <rdar://problem/8516692> ld doesn't pass stabs debug info through to the final executable any longer
 
------ Tagged ld64-96.7
+2010-10-05    Nick Kledzik    <kledzik@apple.com>
 
-2009-08-29     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/4251267> __UNIXSTACK placed incorrectly when -stack_addr < 0x4000000
 
-       <rdar://problem/6933931> Linker makes subtype-zero file from empty subtype-nonzero file.        
+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
        
------ Tagged ld64-96.6
-
-2009-07-30     Nick Kledzik    <kledzik@apple.com>
+2010-10-04    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/7103437> ld: ldr 12-bit displacement out of range on SnowLeopard with gcc-5648
-       * in Section::Section() set fIndex to ensure __symbolstub1 sorts to end of __TEXT segment
+       <rdar://problem/8468240> -no_compact_unwind should suppress dwarf->CUE warnings
 
+-------- tagged ld64-119
 
------ Tagged ld64-96.5
+2010-10-01    Nick Kledzik    <kledzik@apple.com>
 
-2009-07-28     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/6599016> use ld64 to link iBoot
 
-       <rdar://problem/7073626> Thumb mode compilation isn't working on 3.1 beta 2
-       * Fix instructions used in kBranchIslandToThumb1 case
+2010-10-01    Nick Kledzik    <kledzik@apple.com>
 
+       <rdar://problem/8504770> crash when entrypoint is thumb
 
------ Tagged ld64-96.4
+2010-10-01    Nick Kledzik    <kledzik@apple.com>
 
-2009-06-22     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/6992387> platform linker should use platform ld_classic
-       * Fix Options::gotoClassicLinker() to use realpath()s
-       
-
-2009-06-22     Nick Kledzik    <kledzik@apple.com>
-
-       * Fix Options::setIPhoneVersionMin() to handle 2.x through 9.x 
+       If -ios_version_min is used with -arch i386, assume simulator
 
+2010-10-01    Nick Kledzik    <kledzik@apple.com>
 
------ Tagged ld64-96.3
+       <rdar://problem/8500061> crash with multiple re-exported dylibs with same install_name
 
-2009-06-17     Nick Kledzik    <kledzik@apple.com>
+2010-09-28    Nick Kledzik    <kledzik@apple.com>
 
-       * Change section sorting so that arm and ppc stub section is immediately after __text section
+       <rdar://problem/8032130> Linker complains about resolver functions when architecture is inferred.
        
+2010-09-28    Nick Kledzik    <kledzik@apple.com>
 
-2009-06-17     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/6751424> ARM subtype not set on LTO programs
 
-       <rdar://problem/6975041> don't use no-PIC stubs in any dylibs - it might conflict with codesigning
-       * In StubAtom<arm>::StubAtom() don't use kStubNoPIC for OS dylibs
-       
-
------ Tagged ld64-96.2
+2010-09-28    Nick Kledzik    <kledzik@apple.com>
 
-2009-06-09     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
 
-       * Back out page-cross branch work around
+2010-09-24    Nick Kledzik    <kledzik@apple.com>
 
+       <rdar://problem/8441087> Support -dyld_env NAME=value
 
------ Tagged ld64-96.1
+2010-09-23    Nick Kledzik    <kledzik@apple.com>
 
-2009-06-05     Nick Kledzik    <kledzik@apple.com>
-
-       * Fix "duplicate symbol cache-line-crossing-stub" error by giving placeholders unique names
-       * Fix -pie by allowing relocs in x86 stubs and stub helpers
-       
+       Previous BranchIsland code changes to make buildable with clang++ were bad.  Fix.
 
------ Tagged ld64-96
+2010-09-23    Nick Kledzik    <kledzik@apple.com>
 
-2009-06-04     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/8274443> ld64 objc category merging asserts on category from old framework
 
-       * Darwin x86_64 static codegen is really dynamic code gen, so use LTO_CODEGEN_PIC_MODEL_DYNAMIC 
+2010-09-23    Nick Kledzik    <kledzik@apple.com>
 
+       <rdar://problem/8469063> ASLR Sidebuild: Many Projects Fail checksyms_read_only_relocs Verifier
 
-2009-06-03     Nick Kledzik    <kledzik@apple.com>
-       
-       <rdar://problem/6945923> use lto_codegen_set_assembler_path()
+2010-09-22    Nick Kledzik    <kledzik@apple.com>
 
+       Fix DOF section name bug
 
-2009-06-03     Nick Kledzik    <kledzik@apple.com>
+2010-09-22    Nick Kledzik    <kledzik@apple.com>
 
-       * In src/ld/LTOReader.hpp, move where -save-temps .bc file is saved to be after code model set 
+       Fixes to build with clang++
 
+2010-09-21    Nick Kledzik    <kledzik@apple.com>
 
-2009-06-01     Nick Kledzik    <kledzik@apple.com>
-       
-       <rdar://problem/6806033> Link Time Optimization error with 'dead code strip' + hidden symbol
-       * scan newAtoms returned from optimize() looking for ones already in the symbol table
-       * add test case unit-tests/test-cases/lto-dead_strip-all-hidden
+       In Resolver::fillInHelpersInInternalState(), dyld never needs stubs
 
+2010-09-21    Ivan Krstic     <ike@apple.com>
 
-2009-05-19     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/8457083> ld: support non-executable heap Mach-O header flag
 
-       <rdar://problem/6881656> make dyld stubs smaller/faster
-       * Add new addSynthesizedAtoms() method to Writer, called before atoms are sorted
-       * Fix throwf() and warning() to check printf types
-       * Add arm::kPointerDiff12 to support fast arm stubs
-       * Add new ContentType values for stubs and (non)lazy pointers
-       * Add new variant of arm stub this is one instruction
+2010-09-21    Nick Kledzik    <kledzik@apple.com>
 
+       <rdar://problem/8175282> Xcode 4 linker fails with "address not in any section"
 
-2009-05-13     Nick Kledzik    <kledzik@apple.com>
+2010-09-20    Nick Kledzik    <kledzik@apple.com>
 
-       * ld64.xcodeproj/project.pbxproj: add warnings to dyldinfo target
-       * src/other/dyldinfo.cpp: support classic LINKEDIT format
+       <rdar://problem/8198832> assertion failure reading i386 yasm .o (not using scattered reloc)
 
+2010-09-20    Nick Kledzik    <kledzik@apple.com>
 
-2009-05-12     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/8430751> ld crashes when parsing dwarf and all code is not in __text
 
-       * src/ld/MachOWriterExecutable.hpp: fix optimization to skip branch islands with ARM bl instructions
+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
 
-2009-05-12     Nick Kledzik    <kledzik@apple.com>
+2010-09-17    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6836647> creation of __unwind_info section can fail if hundreds of functions cannot be compact encoded
-       * src/ld/MachOWriterExecutable.hpp: fix when to make regular vs compressed pages
+       <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>
 
-2009-05-08     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/8413931> FUN in debug map not rebased
+       Update test case: unit-tests/test-cases/rebase-basic
 
-       * src/ld/ld.cpp: enhance -save-temps to also write out optimized bitcode file
-       
+2010-09-16    Nick Kledzik    <kledzik@apple.com>
 
-2009-05-08     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/8427133> Relocation failure with i386 32-bit diff to stub
 
-       * src/ld/ld.cpp: fix -order_file_statistics to print each symbol not found and correct total
-       
+2010-09-16    Nick Kledzik    <kledzik@apple.com>
 
-2009-05-08     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/8437287> assert when targeting 10.5 and crt1.o/dylib1.o is not supplied
 
-       <rdar://problem/6870522> linker should be able to coalesce UTF16 strings
-       * src/ld/MachOReaderRelocatable.hpp: parse __ustring section by labels but synthesize an
-               atom name based on the content.  Leverage for __cfstring section
-       * unit-tests/test-cases/cfstring-utf16: update test case
+-------- tagged ld64-118.1
 
+2010-09-15    Nick Kledzik    <kledzik@apple.com>
 
-2009-05-07     Nick Kledzik    <kledzik@apple.com>
+       Fix missing rebase commands that broke perl
 
-       * src/ld/MachOWriterExecutable.hpp: put branch islands further apart if there is no thumb code
+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
 
-2009-05-07     Nick Kledzik    <kledzik@apple.com>
+2010-09-13    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6331300> LINKEDIT optimizations for iPhone
-       * src/ld/ObjectFile.h: Recognize iPhoneOS 3.1
-       * src/ld/Options.cpp: iPhoneOS 3.1 => use compressed LINKEDIT
-       * src/ld/MachOWriterExecutable.hpp: support generating compressed LINKEDIT for arm
+       <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>
 
-2009-05-04     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/6723729> LC_UUID uuids should conform to RFC 4122 UUID version 4 & UUID version 5 formats
 
-       <rdar://problem/5716715> Add linker support for ARM branch islands
-       <rdar://problem/5253691> Add labels to linker synthesized jump islands
-       * src/ld/MachOWriterExecutable.hpp: reworked BranchIslandAtom and createBranchIslands to support arm/thumb
-       * src/ld/ObjectFile.h: added kBranchIsland
-       * unit-tests/test-cases/branch-islands: updated test case to check arm/thumb
+2010-09-09    Nick Kledzik    <kledzik@apple.com>
 
+       <rdar://problem/4942948> support -bind_at_load
 
-2009-04-30     Nick Kledzik    <kledzik@apple.com>
+2010-09-07    Nick Kledzik    <kledzik@apple.com>
 
-       * src/ld/Options.cpp: fix custom stack base address for arm
+       <rdar://problem/7989734> ld mis-handling std::tr1::anonymous symbols
+       Remove support for ordering gcc-4.0 compiled anonymous namespace symbols
 
 
-2009-04-30     Nick Kledzik    <kledzik@apple.com>
+-------- tagged ld64-118
 
-       <rdar://problem/6818272> likely incorrect warning about common symbols
-       * src/ld/Options.cpp: ignore LD_WARN_COMMONS in -r mode
-       
+2010-09-02    Nick Kledzik    <kledzik@apple.com>
 
------ Tagged ld64-95.8.3
+       <rdar://problem/8308697> -preload should not have LINKEDIT segment
+       Added test case: unit-tests/test-cases/efi-basic
 
-2009-03-31     Nick Kledzik    <kledzik@apple.com>
+2010-09-02    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6719270> ld might set MH_WEAK_DEFINES when it should not
-       * src/ld/MachOWriterExecutable.hpp: rescan fRegularDefAtomsThatOverrideADylibsWeakDef and only consider global ones
-       
+       <rdar://problem/8389578> trivial Objective-C app fails when using libLTO
+       Added test case: unit-tests/test-cases/lto-objc-image-info
 
------ Tagged ld64-95.8.2
+2010-09-02    Nick Kledzik    <kledzik@apple.com>
 
-2009-03-18     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
 
-       * src/ld/MachOReaderRelocatable.hpp: back out -force_cpusubtype_ALL changes
+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
 
------ Tagged ld64-95.8.1
+2010-09-01    Nick Kledzik    <kledzik@apple.com>
 
-2009-03-17     Nick Kledzik    <kledzik@apple.com>
+       Warn if unaligned ARM code is detected
 
-       <rdar://problem/6578416> -dead_strip inhibits weak coalescing in no_dead_strip section  
-       * src/ld/ld.cpp: in markDead() remove from fLiveRootAtoms
-       
+2010-09-01    Nick Kledzik    <kledzik@apple.com>
        
-2009-03-17     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/8383175> Mach-O linked by current linker don't load in VIrtualBox any more
 
-       <rdar://problem/6671072> libgcc fails to build in with ld64-95.8
-       * src/ld/MachOReaderRelocatable.hpp: interpret CPU_SUBTYPE_ARM_ALL as CPU_SUBTYPE_ARM_V4T
-       * src/ld/Options.cpp: interept -force_cpusubtype_ALL as -arch armv4t
+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
 
------ Tagged ld64-95.8
+2010-09-01    Nick Kledzik    <kledzik@apple.com>
 
-2009-02-09     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/8249338> Enable new load commands
 
-       <rdar://problem/6569316> ld64-95.7 crashes building Foundation-678.39 in side build
-       * src/ld/MachOReaderRelocatable.hpp: handle a zero length section with a label before __cstring section
+2010-09-01    Nick Kledzik    <kledzik@apple.com>
 
+       <rdar://problem/8368679>  Do not pass -demangle to ld_classic
 
------ Tagged ld64-95.7
+2010-09-01    Nick Kledzik    <kledzik@apple.com>
 
-2009-02-06     Nick Kledzik    <kledzik@apple.com>
-
-       * src/ld/ObjectFile.h: make fAddCompactUnwindEncoding false by default
-       
+       <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     
 
-2009-02-06     Nick Kledzik    <kledzik@apple.com>
+-------- tagged ld64-117.11
 
-       <rdar://problem/6537210> ER: add linker option to zero fill empty DATA sections on disk
-       * src/ld/Options.cpp: add support for -no_zero_fill_sections
-       * src/ld/MachOReaderRelocatable.hpp: isZeroFill() is only true if fOptimizeZeroFill 
-       * doc/man/man1/ld.1: document -no_zero_fill_sections
-       * unit-tests/test-cases/no_zero_fill_sections: add test case
-       
+2010-09-03    Nick Kledzik    <kledzik@apple.com>
 
-2009-02-05     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/8385011> mask thumb bit off non lazy pointers content when parsing arm .o files
 
-       <rdar://problem/6497366> label getting resolved to the wrong address.
-       * src/ld/MachOWriterExecutable.hpp: add findAtomAndOffsetForSection() and use it to disambiguate
-       * unit-tests/test-cases/label-on-end-of-section: added test case
+-------- tagged ld64-117.10
 
+2010-08-26    Nick Kledzik    <kledzik@apple.com>
 
-2009-01-27     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
 
-       <rdar://problem/6517393> Warn -force_cpusubtype_ALL is not supported
-       * src/ld/Options.cpp: warn if fForceSubtypeAll and fArchitecture is CPU_TYPE_ARM
-       
+-------- tagged ld64-117.9
 
------ Tagged ld64-95.6
+2010-08-25    Nick Kledzik    <kledzik@apple.com>
 
-2009-01-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
 
-       <rdar://problem/6439020> Add support for section start/end labels
-       * src/ld/ObjectFile.h: add kSectionStart and kSectionEnd
-       * src/ld/MachOReaderRelocatable.hpp: create SectionBoundaryAtoms as needed
-       * src/ld/ld.cpp: sort SectionBoundaryAtoms correctly
-       * src/ld/MachOWriterExecutable.hpp: allow all relocations in preload images
+-------- tagged ld64-117.8
 
+2010-08-25    Nick Kledzik    <kledzik@apple.com>
 
------ Tagged ld64-95.5
+       <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
 
-2009-01-15     Nick Kledzik    <kledzik@apple.com>
+-------- tagged ld64-117.7
 
-       * src/ld/MachOWriterExecutable.hpp: in hasPageCrossingBranches() ignore branches preceeded by a branch
+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-95.4
+-------- tagged ld64-117.6
 
-2009-01-15     Nick Kledzik    <kledzik@apple.com>
+2010-08-23    Nick Kledzik    <kledzik@apple.com>
 
-       * src/ld/Options.cpp: handle -kext and -r the same for fPreventPageCrossingBranches
+       <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
 
------ Tagged ld64-95.3
+2010-08-20    Nick Kledzik    <kledzik@apple.com>
 
-2009-01-14     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/8309595> SWB: ld64-117.1 on Durango8F54: 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
 
-       <rdar://problem/6497574> linker should alter layout to prevent armv7 page crossing branches
-       * src/ld/Options.cpp: set fPreventPageCrossingBranches
-       * src/ld/MachOWriterExecutable.hpp: adjust layout of __text so there are not page crossing branches
-       * src/ld/MachOReaderRelocatable.hpp: support new ARM_THUMB_32BIT_BRANCH reloce
+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
 
------ Tagged ld64-95.2.10
+2010-08-17    Nick Kledzik    <kledzik@apple.com>
 
-2009-04-02    Nick Kledzik    <kledzik@apple.com>
+       Fix resolver functions to survive ld -r.
+       Warn if resolver functions are made non-external.
 
-       <rdar://problem/6805002> corrupt metaclass entry in dynamic library
-       * src/ld/ld.cpp: change Section constructor to copy segment and section names
+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-95.2.9
+-------- tagged ld64-117.3
 
-2009-04-02    Nick Kledzik    <kledzik@apple.com>
+2010-08-17    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6744267> Update ld64 for new triples introduced in 6654669 to support ARM LLVM
-       * src/ld/LTOReader.hpp: change "arm-" to "arm" so matching works for new triples
+       Fix thumb resolver functions
+       Enable updward dylibs and symbol re-exports for iOS 4.2
 
+2010-08-16    Nick Kledzik    <kledzik@apple.com>
 
------ Tagged ld64-95.2.8
+       <rdar://problem/8308697> Latest ld no longer supports EFI -preload
+       Rearrange LINKEDIT chunks in -preload mode
 
-2009-03-24    Nick Kledzik    <kledzik@apple.com>
+-------- tagged ld64-117.2
 
-       <rdar://problem/6713931> anonymous functions have the compact unwind info computed wrong
-       * ld/MachOReaderRelocatable.hpp: use new compact unwind function in AnonymousAtom
+2010-08-14    Nick Kledzik    <kledzik@apple.com>
 
+       <rdar://problem/8308697> Latest ld no longer supports EFI -preload
+       Add LC_UNIXTHREAD to -preload
 
------ Tagged ld64-95.2.7
+2010-08-14    Nick Kledzik    <kledzik@apple.com>
 
-2009-03-11    Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/8309530> SWB: ld64-117.1 on Durango8F54: 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
 
-       <rdar://problem/6670421> AddressBook incorrectly gets _objc_msgSend from WebKit
-       * src/ld/MachOReaderDylib.hpp: fix processIndirectLibraries() to not force a private re-export of a dylib
-                                                                       that is already explictly or implicitly linked.
-       * unit-tests/test-cases/re-export-optimizations-indirect: add test case
-       
+2010-08-14    Nick Kledzik    <kledzik@apple.com>
 
-2009-03-10    Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/8309917> SWB: ld64-117.1 on Durango8F54: bad category optimization
+       Disable category optimization for i386 and arm until further testing
 
-       <rdar://problem/6665853> dyld weak linking optimization leaves some symbols unbound
-       * src/ld/MachOWriterExecutable.hpp: be sure to create bind entry for a reference 
-                                                                               to a symbol in a dylib that is a weak definition
-       * unit-tests/test-cases/coalesce_weak_def_in_dylib: add test case
+2010-08-14    Nick Kledzik    <kledzik@apple.com>
 
+       <rdar://problem/8309608> SWB: ld64-117.1 on Durango8F54: address not in any section
+       Handle pointer diff to stub for weak hidden function
 
-2009-03-10    Nick Kledzik    <kledzik@apple.com>
+2010-08-13    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6666004> many OS i386 OS dylibs still have __IMPORT segment
-       * ld/MachOReaderRelocatable.hpp: moved where __IMPORT/__pointer is changed to __DATA/__nl_symbol_ptr
-       * unit-tests/test-cases/stripped-indirect-symbol-table:  updated to test for this problem
+       <rdar://problem/8308697> Latest ld no longer supports EFI -preload
 
+-------- tagged ld64-117.1
 
------ Tagged ld64-95.2.6
+2010-08-11    Nick Kledzik    <kledzik@apple.com>
 
-2009-02-27     Nick Kledzik    <kledzik@apple.com>
+       Make missing exported symbols a warning to help adoption of new linker
 
-       <rdar://problem/6633530> ld might set MH_WEAK_DEFINES when it should not
-       * src/ld/MachOWriterExecutable.hpp: only consider atoms in fRegularDefAtomsThatOverrideADylibsWeakDef
-                                                                               that will be exported when computing MH_WEAK_DEFINES
-       * unit-tests/test-cases/operator-new: updated to reproduce issue
-       
+2010-08-11    Nick Kledzik    <kledzik@apple.com>
 
------ Tagged ld64-95.2.5
+       Add ExternalRelocationsAtom<>::pointerReloc() to more easily support kext bundles
 
-2009-02-24     Nick Kledzik    <kledzik@apple.com>
+2010-08-09    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6605499> x86_64 obj-c runtime confused when static lib is stripped
-       * src/ld/MachOWriterExecutable.hpp: in setLocalNlist() don't use 'l' labels for x86_64 strings
-       * unit-tests/test-cases/objc-literal-pointers-strip: added test case
-       
+       <rdar://problem/8210380> SWB: ld64-116.2 fix branch to label-4
 
------ Tagged ld64-95.2.4
+2010-08-09    Nick Kledzik    <kledzik@apple.com>
 
-2009-02-23     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/8260073> Error with empty non_lazy_symbol_pointers section
 
-       * src/ld/MachOReaderRelocatable.hpp: ignore ARM_THUMB_32BIT_BRANCH relocs
+2010-08-06    Nick Kledzik    <kledzik@apple.com>
 
+       <rdar://problem/7977374> Add command line options to control symbol weak-def-bit on exported symbols
 
-2009-02-18     Nick Kledzik    <kledzik@apple.com>
+-------- tagged ld64-117
 
-       <rdar://problem/6583555> Writer<A>::symbolIndex() uses a linear search and does not scale
-       * src/ld/MachOWriterExecutable.hpp: build a std::map so symbolIndex() scales better
-       
+2010-07-28    Nick Kledzik    <kledzik@apple.com>
 
-2009-02-18     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/8243431> split seg info wrong for x86_64 stub helpers
 
-       <rdar://problem/6312070> Use new compact encodings that handle all register permutations
-       * src/ld/Architectures.hpp: add kSectionOffset24
-       * src/ld/ObjectFile.h: add getFDE()
-       * src/ld/MachOReaderRelocatable.hpp: use new libunwind functions to get new compact encoding
-       * src/ld/MachOWriterExecutable.hpp: use new compact encoding which includes offset in dwarf if needed
-       * src/other/unwinddump.cpp: update unwinddump output to display register save set
-       
+2010-07-26    Nick Kledzik    <kledzik@apple.com>
 
-2009-02-16     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/8237436> __nlcatlist categories should not be optimized
 
-       <rdar://problem/6511619> runtime error with bundle for 10.5 that has weak external symols
-       * src/ld/ld.cpp: fix hybrid (10.5) compressed linkedit info for data pointing to weak definitions
-       
+2010-07-23    Nick Kledzik    <kledzik@apple.com>
 
-2009-02-15     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/8179273> ld64 assertion on object file
 
-       <rdar://problem/6583757> i386 relocation error with negative offsets from local labels
-       * src/ld/MachOReaderRelocatable.hpp: handle when base addr of scattered relocation does not point to a label
-       * unit-tests/test-cases/relocs-neg-from-local: add test case
-       
+2010-07-21    Nick Kledzik    <kledzik@apple.com>
 
-2009-02-12     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/7435296> Reorder sections to reduce page faults in object files
 
-       <rdar://problem/6578360> -dead_strip inhibits weak coalescing in no_dead_strip section
-       * src/ld/ld.cpp: remove atoms coalesced away from fLiveRootAtoms
-       * unit-tests/test-cases/dead_strip-weak-coalesce: added test case
+2010-06-30    Nick Kledzik    <kledzik@apple.com>
 
+       Support resolver functions in iOS dylibs
 
-2009-02-12     Nick Kledzik    <kledzik@apple.com>
+-------- tagged ld64-116.2
 
-       <rdar://problem/6581809> x86_64 weak_import broken for initialized data
-       * src/ld/MachOReaderRelocatable.hpp: use isWeakImportSymbol() in Reader<x86_64>::addRelocReference()
-       * src/other/dyldinfo.cpp: update to display weak_import attribute
-       * unit-tests/test-cases/weak_import: updated test case
+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
 
-2009-02-06     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/6541812> ld parsing of __eh_frame unwind information is slow
-       * src/ld/MachOReaderRelocatable.hpp: build a std::map of all __eh_frame relocations for x86_64
-
+-------- tagged ld64-116.1
 
------ Tagged ld64-95.2.3
+2010-06-22    Nick Kledzik    <kledzik@apple.com>
 
-2009-02-04     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/8111013> address range check should not apply to preload executables
 
-       <rdar://problem/6545406> ld: warning: can't add line info to anonymous symbol
-       * src/ld/MachOReaderRelocatable.hpp: don't warn about line info in dyld stubs
+2010-06-22    Nick Kledzik    <kledzik@apple.com>
 
+       Warn instead of error when CPU_SUBTYPE_ARM_ALL .o files used.
 
------ Tagged ld64-95.2.2
+2010-06-22    Nick Kledzik    <kledzik@apple.com>
 
-2009-02-02     Nick Kledzik    <kledzik@apple.com>
+       Fix assert in objc category optimzation.  Metaclass also has copy of propery list to update.
 
-       <rdar://problem/6548268> ld -r does not preserve the N_NO_DEAD_STRIP bit
-       * src/ld/MachOWriterExecutable.hpp: set N_NO_DEAD_STRIP based on dontDeadStrip()
-       * unit-tests/test-cases/dead_strip-r_symbol_desc: added test case
+2010-06-22    Nick Kledzik    <kledzik@apple.com>
 
+       Fix crash in -r mode with -alias.
 
------ Tagged ld64-95.2.1
+-------- tagged ld64-116
 
------ Tagged ld64-95.2.10
+2010-06-21    Nick Kledzik    <kledzik@apple.com>
 
-2009-04-02    Nick Kledzik    <kledzik@apple.com>
+       Add support for -ios_version_min as an alias for -iphoneos_version_min
 
-       <rdar://problem/6805002> corrupt metaclass entry in dynamic library
-       * src/ld/ld.cpp: change Section constructor to copy segment and section names
+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
 
------ Tagged ld64-95.2.9
+2010-06-21    Nick Kledzik    <kledzik@apple.com>
 
-2009-04-02    Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/8113877> i386 TLV PIC reloc content is negated
 
-       <rdar://problem/6744267> Update ld64 for new triples introduced in 6654669 to support ARM LLVM
-       * src/ld/LTOReader.hpp: change "arm-" to "arm" so matching works for new triples
+2010-06-15    Nick Kledzik    <kledzik@apple.com>
 
+       Added better error messages and asserts for bad thread local object files
 
------ Tagged ld64-95.2.8
+2010-06-09    Nick Kledzik    <kledzik@apple.com>
 
-2009-03-24    Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/8076986> Barolo: 'rebase' makes timestamps invalid/unreadable for GDB
 
-       <rdar://problem/6713931> anonymous functions have the compact unwind info computed wrong
-       * ld/MachOReaderRelocatable.hpp: use new compact unwind function in AnonymousAtom
+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
 
------ Tagged ld64-95.2.7
+2010-06-09    Nick Kledzik    <kledzik@apple.com>
 
-2009-03-11    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
 
-       <rdar://problem/6670421> AddressBook incorrectly gets _objc_msgSend from WebKit
-       * src/ld/MachOReaderDylib.hpp: fix processIndirectLibraries() to not force a private re-export of a dylib
-                                                                       that is already explictly or implicitly linked.
-       * unit-tests/test-cases/re-export-optimizations-indirect: add test case
-       
-
-2009-03-10    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/6665853> dyld weak linking optimization leaves some symbols unbound
-       * src/ld/MachOWriterExecutable.hpp: be sure to create bind entry for a reference 
-                                                                               to a symbol in a dylib that is a weak definition
-       * unit-tests/test-cases/coalesce_weak_def_in_dylib: add test case
-
-
-2009-03-10    Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/6666004> many OS i386 OS dylibs still have __IMPORT segment
-       * ld/MachOReaderRelocatable.hpp: moved where __IMPORT/__pointer is changed to __DATA/__nl_symbol_ptr
-       * unit-tests/test-cases/stripped-indirect-symbol-table:  updated to test for this problem
-
-
------ Tagged ld64-95.2.6
+2010-06-04    Nick Kledzik    <kledzik@apple.com>
 
-2009-02-27     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/6144674> ER: individual symbol re-exports
+       Added test case: unit-tests/test-cases/re-export-symbo
 
-       <rdar://problem/6633530> ld might set MH_WEAK_DEFINES when it should not
-       * src/ld/MachOWriterExecutable.hpp: only consider atoms in fRegularDefAtomsThatOverrideADylibsWeakDef
-                                                                               that will be exported when computing MH_WEAK_DEFINES
-       * unit-tests/test-cases/operator-new: updated to reproduce issue
-       
-
------ Tagged ld64-95.2.5
-
-2009-02-24     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/6605499> x86_64 obj-c runtime confused when static lib is stripped
-       * src/ld/MachOWriterExecutable.hpp: in setLocalNlist() don't use 'l' labels for x86_64 strings
-       * unit-tests/test-cases/objc-literal-pointers-strip: added test case
-       
+2010-06-03    Nick Kledzik    <kledzik@apple.com>
 
------ Tagged ld64-95.2.4
+       <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
 
-2009-02-23     Nick Kledzik    <kledzik@apple.com>
+2010-06-02    Nick Kledzik    <kledzik@apple.com>
 
-       * src/ld/MachOReaderRelocatable.hpp: ignore ARM_THUMB_32BIT_BRANCH relocs
+       <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>
 
-2009-02-18     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/8040089> provide better undefined symbol error message
 
-       <rdar://problem/6583555> Writer<A>::symbolIndex() uses a linear search and does not scale
-       * src/ld/MachOWriterExecutable.hpp: build a std::map so symbolIndex() scales better
-       
+2010-05-28    Nick Kledzik    <kledzik@apple.com>
 
-2009-02-18     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
 
-       <rdar://problem/6312070> Use new compact encodings that handle all register permutations
-       * src/ld/Architectures.hpp: add kSectionOffset24
-       * src/ld/ObjectFile.h: add getFDE()
-       * src/ld/MachOReaderRelocatable.hpp: use new libunwind functions to get new compact encoding
-       * src/ld/MachOWriterExecutable.hpp: use new compact encoding which includes offset in dwarf if needed
-       * src/other/unwinddump.cpp: update unwinddump output to display register save set
-       
+2010-05-28    Nick Kledzik    <kledzik@apple.com>
 
-2009-02-16     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
 
-       <rdar://problem/6511619> runtime error with bundle for 10.5 that has weak external symols
-       * src/ld/ld.cpp: fix hybrid (10.5) compressed linkedit info for data pointing to weak definitions
-       
+-------- tagged ld64-115.3
 
-2009-02-15     Nick Kledzik    <kledzik@apple.com>
+2010-05-26    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6583757> i386 relocation error with negative offsets from local labels
-       * src/ld/MachOReaderRelocatable.hpp: handle when base addr of scattered relocation does not point to a label
-       * unit-tests/test-cases/relocs-neg-from-local: add test case
-       
+       * <rdar://problem/8024702> strip of .o files removes __objc_imageinfo section
+       * Added test case:  unit-tests/test-cases/dwarf-strip-objc
 
-2009-02-12     Nick Kledzik    <kledzik@apple.com>
+2010-05-25    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6578360> -dead_strip inhibits weak coalescing in no_dead_strip section
-       * src/ld/ld.cpp: remove atoms coalesced away from fLiveRootAtoms
-       * unit-tests/test-cases/dead_strip-weak-coalesce: added test case
+       * <rdar://problem/8023624> crash when parsing local vanilla reloc to weak def
 
+-------- tagged ld64-115.2
 
-2009-02-12     Nick Kledzik    <kledzik@apple.com>
+2010-05-21    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6581809> x86_64 weak_import broken for initialized data
-       * src/ld/MachOReaderRelocatable.hpp: use isWeakImportSymbol() in Reader<x86_64>::addRelocReference()
-       * src/other/dyldinfo.cpp: update to display weak_import attribute
-       * unit-tests/test-cases/weak_import: updated test case
+       * <rdar://problem/8012536> switch back to using ld_classic for -static arm code
        
 
-2009-02-06     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/6541812> ld parsing of __eh_frame unwind information is slow
-       * src/ld/MachOReaderRelocatable.hpp: build a std::map of all __eh_frame relocations for x86_64
-
-
------ Tagged ld64-95.2.3
-
-2009-02-04     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/6545406> ld: warning: can't add line info to anonymous symbol
-       * src/ld/MachOReaderRelocatable.hpp: don't warn about line info in dyld stubs
-
-
------ Tagged ld64-95.2.2
+2010-05-21    Nick Kledzik    <kledzik@apple.com>
 
-2009-02-02     Nick Kledzik    <kledzik@apple.com>
+       * <rdar://problem/8012549> warn instead of error when seg1addr is out of range for ARM
 
-       <rdar://problem/6548268> ld -r does not preserve the N_NO_DEAD_STRIP bit
-       * src/ld/MachOWriterExecutable.hpp: set N_NO_DEAD_STRIP based on dontDeadStrip()
-       * unit-tests/test-cases/dead_strip-r_symbol_desc: added test case
 
+2010-05-21    Nick Kledzik    <kledzik@apple.com>
 
------ Tagged ld64-95.2.1
+       * <rdar://problem/8012526> fix -undefined dynamic_lookup -nodefaults to not error about missing dyld_stub_binder
 
-2009-01-29     Nick Kledzik    <kledzik@apple.com>
+-------- tagged ld64-115.1
 
-       <rdar://problem/6532377> gcc DejaGnu failure: building longcall/dylib library
-       * src/ld/MachOWriterExecutable.hpp: if no __DATA sections insert non-lazy pointers at end of __TEXT segment
-       * unit-tests/test-cases/no-data-bundle: added test case
+2010-05-19    Nick Kledzik    <kledzik@apple.com>
 
+       * Fix trie nodes for resolver functions to have second address be stub not helper               
 
------ Tagged ld64-95.2
-
-2009-01-06     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/6476760> strip -S fails with "new trie is larger than original"
-       * src/other/PruneTrie.cpp: don't align trie more than original trie was aligned
-       
-
------ Tagged ld64-95.1
-
-2008-12-21     Nick Kledzik    <kledzik@apple.com>
-
-        * src/ld/MachOWriterExecutable.hpp: in new linkedit format, make sure only exported symbols
-                                       make it into weak binding info
-       
-       
------ Tagged ld64-95
+2010-05-19    Nick Kledzik    <kledzik@apple.com>
 
-2008-12-18     Nick Kledzik    <kledzik@apple.com>
+       * <rdar://problem/7996423> work around for old checksyms tools  
+       * Make i386 stub section named "__symbol_stub" instead of "__stubs"
 
-       * src/ld/Options.cpp: move check for fSharedRegionEligible until fPrebind has stabilized
-       
+2010-05-10    Nick Kledzik    <kledzik@apple.com>
 
-2008-12-18     Nick Kledzik    <kledzik@apple.com>
+       * <rdar://problem/7960396> linking with LTO prints "/tmp/lto.o"
 
-       <rdar://problem/6305021> Generate new compressed LINKEDIT when targeting 10.6
-       * src/ld/Options.cpp: turn on compressed LINKEDIT by default
-       
+-------- tagged ld64-115
 
------ Tagged ld64-94.1
+2010-05-06    Nick Kledzik    <kledzik@apple.com>
 
-2008-12-16     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
 
-       * src/ld/Options.cpp: Fix -F handling in buildSearchPaths()
+2010-05-05    Nick Kledzik    <kledzik@apple.com>
 
+       * rework min OS version parsing to enable the linker to handle unknown OS versions
 
------ Tagged ld64-94
 
-2008-12-15     Nick Kledzik    <kledzik@apple.com>
+2010-05-05    Nick Kledzik    <kledzik@apple.com>
 
-       * doc/man/man1/ld.1: document new options
+       * 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
        
 
-2008-12-15     Nick Kledzik    <kledzik@apple.com>
+2010-05-03    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6134468> linker should enforce all .o files have same sub-type, and ignore sub-type of dylibs
-       * doc/man/man1/ld.1: update man page about -allow_sub_type_mismatches
-       * src/ld/ld.cpp: call validFile() with new arguments
-       * src/ld/MachOReaderRelocatable.hpp: add new arguments to validFile()
-       * src/ld/Options.cpp: Support LD_ALLOW_CPU_SUBTYPE_MISMATCHES and -allow_sub_type_mismatches
+       * <rdar://problem/7173071> implement optional demangling in linker
+       * Add option: -demangle
+       * Add test case: unit-tests/test-cases/demangle
        
 
-2008-12-15     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/6438270> -syslibroot should skip standard search paths not in the SDK
-       * src/ld/Options.cpp: in buildSearchPaths() if an SDK is specified don't add 
-                                                       standard search paths not in the SDK.
-
-
-2008-12-15     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/6406609> ld: remove "can't make compact unwind encoding" warning
-       * src/ld/ObjectFile.h: add fWarnCompactUnwind
-       * src/ld/Options.cpp: -warn_compact_unwind --> fWarnCompactUnwind
-       * src/ld/MachOReaderRelocatable.hpp: test fWarnCompactUnwind before warning
-
-
-2008-12-15     Nick Kledzik    <kledzik@apple.com>
+2010-05-03    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6442926> Add dtrace usdt support for arm to ld64
-       * src/ld/MachOWriterExecutable.hpp: handle arm::kDtraceIsEnabledSite
-       * unit-tests/test-cases/dtrace-static-probes: use is-enabled in test case
+       * <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
 
 
------ Tagged ld64-93
+2010-05-03    Nick Kledzik    <kledzik@apple.com>
 
-2008-12-11     Nick Kledzik    <kledzik@apple.com>
-
-       * src/ld/ObjectFile.h: add fIPhoneVersionMin to track min iPhoneOS version
-       * src/ld/Options.cpp: use fIPhoneVersionMin 
+       * <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
        
 
-2008-12-11     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/6431277> non-lazy pointer to non-global tentative definition encoded wrong
-       * src/ld/MachOWriterExecutable.hpp: don't use INDIRECT_SYMBOL_LOCAL for tentative definitions
-       * unit-tests/test-cases/non-lazy-r: updated test case
-
-
-2008-12-11     Nick Kledzik    <kledzik@apple.com>
+2010-04-28    Nick Kledzik    <kledzik@apple.com>
        
-       <rdar://problem/6437667> kernel fails to boot when ld64 used for intermediate ld -r step
-       * src/ld/MachOWriterExecutable.hpp: in -r mode when generating a scattered sect-diff reloc for
-                                                                       i386/arm, special case when from target is not the atom 
-                                                                       the relocation is in.
-       * unit-tests/test-cases/relocs-asm: update test case
+       * <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
        
 
-2008-12-11     Nick Kledzik    <kledzik@apple.com>
-
-       * src/ld/ld.cpp: handle new __program_vars section
-       * src/ld/MachOWriterExecutable.hpp: handle inserting synthesized sections when there is no __dyld section
-
-
-2008-12-11     Nick Kledzik    <kledzik@apple.com>
-
-       * src/ld/MachOReaderRelocatable.hpp: Fix getDescription() to work when direct reference is to anonymous atom
+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
 
-2008-12-10     Nick Kledzik    <kledzik@apple.com>
 
-       * src/ld/Options.cpp: enable LD_FORCE_NO_PREBIND to be used with arm
+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
 
-2008-12-10     Nick Kledzik    <kledzik@apple.com>
-       
-       <rdar://problem/6258169> Developer tool to print the new compressed LINKEDIT information
-       * src/other/dyldinfo.cpp: fix typo in usage()
-       
-
-2008-12-05     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/6308882> SnowLeopard kernel should compile warning free
-       * src/ld/MachOReaderRelocatable.hpp: correct parse two global labels at end of section and make one an alias
-       * unit-tests/test-cases/end-label: update test case
+2010-04-26    Nick Kledzik    <kledzik@apple.com>
 
+       * <rdar://problem/7666015> The documentation for the -allowable_client option doesn't say enough about it
 
-2008-12-04     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/6342245> Better warning than "PPC_RELOC_JBSR should not be using an external relocation"
-       * src/ld/MachOReaderRelocatable.hpp: issue warning with .o path if it was compiled with -mlong-branch
-
-
-2008-12-04     Nick Kledzik    <kledzik@apple.com>
-       
-       <rdar://problem/6408832> linker should not map __pointers -> __nl_symbol_ptr unless actually making new LINKEDIT
-       * src/ld/ObjectFile.h: add fMakeCompressedDyldInfo for readers to see
-       * src/ld/Options.cpp: set fMakeCompressedDyldInfo for readers to see
-       * src/ld/MachOReaderRelocatable.hpp: check fMakeCompressedDyldInfo
+2010-04-26    Nick Kledzik    <kledzik@apple.com>
 
+       * <rdar://problem/7854068> back out LD_NO_PIE
 
-2008-12-02     Nick Kledzik    <kledzik@apple.com>
+2010-04-22    Nick Kledzik    <kledzik@apple.com>
 
-       * src/ld/debugline.c: fix error handling in line_open()
+       * <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
        
 
-2008-11-26     Nick Kledzik    <kledzik@apple.com>
+-------- tagged ld64-114.12
 
-       <rdar://problem/6401277> vtable with thumb entries broke after ld -r
-       * src/ld/MachOReaderRelocatable.hpp: if target of reloc is thumb, mask thumb bit off addend
-       * unit-tests/test-cases/thumb-pointer: added test case
+2010-04-14    Nick Kledzik    <kledzik@apple.com>
 
-
-2008-11-26     Nick Kledzik    <kledzik@apple.com>
-
-       * src/ld/Option.cpp: Fix how crashreporterBuffer is created to not miss some arguments
+       * <rdar://problem/7811357> Crash with messed up BNSYM
        
 
-2008-11-24     Nick Kledzik    <kledzik@apple.com>
+2010-04-07    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6398605> Security.framework has some duplicate FDEs for some functions
-       * src/ld/ld.cpp: remove fDeadAtoms from fLiveAtoms when there are weak atoms overriden by late loads
-       * unit-tests/test-cases/dead_strip-archive-eh: added test case
+       * Fix crash with blank dylib stubs
 
+-------- tagged ld64-114.11
 
------ Tagged ld64-92
+2010-04-07    Nick Kledzik    <kledzik@apple.com>
 
-2008-11-21     Nick Kledzik    <kledzik@apple.com>
-
-       * src/ld/MachOReaderDylib.hpp: if export_size is zero, no need to parse trie
-       * src/abstraction/MachOTrie.hpp: gracefully handle empty trie
+       * <rdar://problem/7798495> for ppc, add split-seg info for TEXT pointers to DATA
        
 
-2008-11-21     Nick Kledzik    <kledzik@apple.com>
+2010-04-07    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6257854> strip(1) support for new compressed LINKEDIT information
-       * ld64.xcodeproj/project.pbxproj: build and install new libprunetrie.a
-       * src/other/prune_trie.h: added
-       * src/other/PruneTrie.cpp: implements prune_trie()
-       
+       * <rdar://problem/7831379> Cannot build ppc64 target with ObjC code
 
-2008-11-21     Nick Kledzik    <kledzik@apple.com>
 
-       * src/ld/ld.cpp: if an export file is used and all weak symbols are masked, don't set WEAK_DEFINES
-       * unit-tests/test-cases/weak-def-flag: added test case
+2010-04-01    Nick Kledzik    <kledzik@apple.com>
 
+       * let .exp files override auto-hide so that they can be exported if needed
 
-2008-11-20     Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6305021> Generate new compressed LINKEDIT when targeting 10.6
-       * src/ld/MachOWriterExecutable.hpp: support generating new compressed format
-       * src/ld/MachOReaderRelocatable.hpp: new compress format implies non-lazy pointers in __DATA for i386
-       * src/ld/MachOReaderDylib.hpp: support linking aginst new format
-       * src/ld/Options.cpp: suppport -exported_symbols_order and -no_compact_linkedit
-       * src/ld/ld.cpp: track which atoms have weak counter parts in dylibs
-       * src/other/dyldinfo.cpp: added tool to display new LINKEDIT format
-       * ld64.xcodeproj/project.pbxproj: add dyldinfo tool
-       * unit-tests/*: lots of fixes to work with new format
+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
 
-2008-11-20     Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6389316> ld64 should preserve N_WEAK_REF when linking MH_KEXT_BUNDLEs
-       * src/ld/MachOWriterExecutable.hpp: set up fWeakImportMap in synthesizeKextGOT() 
+2010-04-01    Nick Kledzik    <kledzik@apple.com>
 
+       * <rdar://problem/7818475> 'l' symbols not being automatically removed
 
-2008-11-19     Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6342406> VideoToolbox.framework has bad __TEXT.__eh_frame info
-       * src/ld/Options.cpp: add -no_eh_labels option for use with -r
-       * src/ld/MachOWriterExecutable.hpp: generate correct x86_64 labeless relocs in -r mode
-       * src/ld/MachOReaderRelocatable.hpp: now ignore all labels and relocations in
-               __TEXT/__eh_frame section and rely on getCFIs() from libunwind
-       * unit-tests/test-cases/eh-coalescing-no-labels: add test case
+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
 
-2008-11-19     Nick Kledzik    <kledzik@apple.com>
+-------- tagged ld64-114.10
 
-       <rdar://problem/6378110> LTO doesn't like dtrace symbols
-       * src/ld/LTOReader.hpp: ignore __dtrace_probe undefines in bitcode files
+2010-03-31    Nick Kledzik    <kledzik@apple.com>
        
+       * <rdar://problem/7735120> assert with .o file with two LSDA sections
 
-2008-11-14     Nick Kledzik    <kledzik@apple.com>
 
-       * src/abstraction/MachOFileAbstraction.hpp: fix to work with 10.5 headers
-       
-       
------ Tagged ld64-91
+-------- tagged ld64-114.9
 
-2008-11-07     Nick Kledzik    <kledzik@apple.com>
-
-       Remove COMPACT_UNWIND_SUPPORT conditionalizing
+2010-03-30    Nick Kledzik    <kledzik@apple.com>
        
-
-2008-11-06     Nick Kledzik    <kledzik@apple.com>
-
-       Reorganize source layout.  ld sources are now in "ld",
-       and other tools are in "other".
+       * <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
        
 
-2008-11-05     Nick Kledzik    <kledzik@apple.com>
-
-       * ld64.xcodeproj/project.pbxproj: start installing unwinddump tool
-       * src/UnwindDump.cpp: support -arch option
-       * doc/man/man1/unwinddump.1: create man page
-
-
-2008-11-05     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/6337329> linker should put cpusubtype in n_sect field of nlist entry for N_OSO debug note entries
-       * src/ld.cpp: in synthesizeDebugNotes() set other field of OSO to be subtype
-
-
-2008-11-05     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/3738966> Need a linker option to load all objects from one library
-       * src/Options.cpp: support -force_load option
-       * src/ArchiveReader.hpp: Add fForceLoad ivar
-       * doc/man/man1/ld.1:  update man page with -force_load option
-       * unit-tests/test-cases/archive-force-load: add test case
+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
 
-2008-11-05     Nick Kledzik    <kledzik@apple.com>
+-------- tagged ld64-114.8
 
-       <rdar://problem/6308882> Dtrace Probe Warnings: SnowLeopard kernel should compile warning free
-       * src/ld.cpp: don't generate GSYM stabs for old style __dtrace_probe
-       * src/MachOReaderRelocatable.hpp: fix test for deciding if a symbol is an alias
-       
-
-2008-11-04     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/6294378> ADOBE: XCODE: ld: duplicate typeinfo in executable
-       * src/ld.cpp: in dead-strip mode, record overriden symbols and later rebind all uses
-       * unit-tests/test-cases/dead_strip-archive-weak: add test case
-       
+2010-03-26    Nick Kledzik    <kledzik@apple.com>
 
-2008-11-03     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
 
-       <rdar://problem/6254202> support increased branch range in Thumb-2
-       * src/MachOReaderRelocatable.hpp: handle full branch range in addRelocReference()
-       * unit-tests/test-cases/branch-distance: added test case
+-------- tagged ld64-114.7
        
-2008-10-31     Devang Patel    <dpatel@apple.com>
-
-       <rdar://problem/5725712> Sqlite 3.5.4 built with lvm-gcc-4.2 -O4 fails regression test
-       * src/LTOReader.hpp: Use real atom scope when real atom is available.
-       Preserve globals while optimizing an executable.
-
-2008-10-30     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.hpp: support all encodings in getEncodedP()
-
+2010-03-25    Nick Kledzik    <kledzik@apple.com>
 
------ Tagged ld64-90
+       * <rdar://problem/7796313> Support LD_NO_PIE again
 
-2008-10-30     Nick Kledzik    <kledzik@apple.com>
+2010-03-25    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6327584> icc has dwarf unwind info that is different than gcc
-       * src/MachOReaderRelocatable.hpp: support more encodings in getEncodedP()
+       * <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>
 
-2008-10-23     Nick Kledzik    <kledzik@apple.com>
+       * <rdar://problem/7786326> Page Zero segment seems to be getting dead stripped
 
-       <rdar://problem/6088653> build ld64 for x86_64
-       * ld64.xcodeproj/project.pbxproj: add X86_64 to valid archs
-       
-
-2008-10-23     Nick Kledzik    <kledzik@apple.com>
+2010-03-24    Nick Kledzik    <kledzik@apple.com>
 
-       * ld64.xcodeproj/project.pbxproj: use generated @$(DERIVED_FILE_DIR)/linker_opts for extra
-               linker options.  This allows linker to be built if LTO headers and libs are missing.
+       * <rdar://problem/7785574> kernel sdt dtrace probes not visible
 
+-------- tagged ld64-114.6
 
-2008-10-23     Nick Kledzik    <kledzik@apple.com>
+2010-03-23    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6273617> Linker warning not shown in the Xcode build log
-       * src/Options.cpp: add colon to format string in warning()
+       * <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
 
------ Tagged ld64-89.3
+2010-03-22    Nick Kledzik    <kledzik@apple.com>
 
-2008-10-24     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
        
-       <rdar://problem/6317985> ld64-89 broke TOT OpenGL libProgrammability x86_64 build       
-       * src/MachOReaderRelocatable.hpp: add cast in getEncodedP()
-       
-
------ Tagged ld64-89.2
 
-2008-10-23     Nick Kledzik    <kledzik@apple.com>
+2010-03-19    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6312895> SnowLeopard: Libsystem built with ld64-89.1 causes crashes
-       * src/MachOReaderRelocatable.hpp: when FDE information causes __text atom to be split, make the 
-                       atoms follow-on pairs.
+       * <rdar://problem/7772740> ld64-114 does not error on missing exported symbols with -dead_strip
 
-
------ Tagged ld64-89.1
-
-2008-10-22     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.hpp: for x86_64 __eh_frame force direct references
+-------- tagged ld64-114.4
        
+2010-03-16    Nick Kledzik    <kledzik@apple.com>
 
-2008-10-21     Nick Kledzik    <kledzik@apple.com>
-
-       * src/ObjectDump.cpp: Use getContentType() to see if content type is a cstring
+       * <rdar://problem/7762146> dyld missing LC_ID_DYLINKER
        
+-------- tagged ld64-114.3
 
------ Tagged ld64-89
+2010-03-15    Nick Kledzik    <kledzik@apple.com>
 
-2008-10-21     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
 
-       <rdar://problem/6253171> 10A180 with QT-1119 roots: iTunes and QuickTime cannot play back purchased videos
-       <rdar://problem/5950453> linker should not need .eh labels
-       * src/MachOWriterExecutable.hpp: use kCFIType to set section attributes
-       * src/MachOReaderRelocatable.hpp: use libunwind's CFITuple to parse __eh_frame content
-       * src/ld.cpp: Add adjustScope() phase instead of demoting scope within symboltable.add()
-       * unit-tests/test-cases/eh-stripped-symbols: added test case
 
+-------- tagged ld64-114.2
 
------ Tagged ld64-88.1
+2010-03-13    Nick Kledzik    <kledzik@apple.com>
 
-2008-10-16     Nick Kledzik    <kledzik@apple.com>
+       * <rdar://problem/7751930> ld64-114 generates x86_64 kext external call sites with incorrect addend
 
-       * src/MachOReaderRelocatable.hpp: Fix uses of COMPACT_UNWIND_SUPPORT
-       * src/MachOWriterExecutable.hpp: Fix uses of COMPACT_UNWIND_SUPPORT
+-------- tagged ld64-114.1
 
+2010-03-12    Nick Kledzik    <kledzik@apple.com>
 
-2008-09-30     Nick Kledzik    <kledzik@apple.com>
+       * Fix dyldinfo tool to correct show ordinal info for classic linkedit
 
-       <rdar://problem/6255983> OBJC2: Reorder __DATA,__objc_* sections by writedness
-       * src/ld.cpp: change sorting order of Sections
+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.
 
-2008-09-29     Nick Kledzik    <kledzik@apple.com>
+-------- tagged ld64-114
 
-       <rdar://problem/6159479> Executable produced by XCode 3.2 on 10.6 crashes on 10.3.9
-       * src/MachOWriterExecutable.hpp: set objc_module_info_addr field of module table
-       
-
------ Tagged ld64-88
-
-2008-09-25     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5935708> kexts need to be built as MH_BUNDLE mach-o files
-       * src/ld.cpp: use getUndefinedProxyAtom() with kKextBundle
-       * src/MachOFileAbstraction.hpp: add MH_KEXT_BUNDLE
-       * src/Options.cpp: support -kext for all architectures
-       * src/MachOWriterExecutable.hpp: support kKextBundle to make a bundle like kext
-       * unit-tests/test-cases/kext-basic: added test case
-       
-
-2008-09-25     Nick Kledzik    <kledzik@apple.com>
+2010-03-11    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6052546> ld invoking wrong ld_classic
-       * src/Options.cpp: first look for ld_classic relative to ld itself
-       
+       * <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
 
-2008-09-25     Nick Kledzik    <kledzik@apple.com>
+-------- tagged ld64-113
 
-       <rdar://problem/5855588> ld fails to link references from 32 bit code into 64 bit code
-       <rdar://problem/5955200> Desired 32-bit absolute relocation
-       * src/Architectures.hpp: add x86_64::kPointer32
-       * src/MachOReaderRelocatable.hpp: support X86_64_RELOC_UNSIGNED with length=2
-       * src/MachOWriterExecutable.hpp: support x86_64::kPointer32
-       * unit-tests/test-cases/relocs-asm/relocs-asm.s: added 32-bit pointer tests
-       
+2010-03-11    Nick Kledzik    <kledzik@apple.com>
 
-2008-09-25     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/6075323> Should be able to mark dylibs as auto-dead-dylib-strip
-       * src/Options.h: add fMarkDeadStrippableDylib
-       * src/MachOReaderDylib.hpp: check MH_DEAD_STRIPPABLE_DYLIB
-       * src/ObjectFile.h: add deadStrippable()
-       * src/MachOFileAbstraction.hpp: add MH_DEAD_STRIPPABLE_DYLIB
-       * src/Options.cpp: support -mark_dead_strippable_dylib
-       * src/MachOWriterExecutable.hpp: test reader->deadStrippable(), set MH_DEAD_STRIPPABLE_DYLIB
-       * doc/man/man1/ld.1: update man page
-       * unit-tests/test-cases/dead_strippable_dylib: added test case
-       
+       * Allow CPU_SUBTYPE_ARM_ALL .o files to be linked into any arm arch linkage
 
-2008-09-25     Nick Kledzik    <kledzik@apple.com>
+2010-03-11    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6197601> ER: Add -seg_page_size option
-       * src/Options.cpp: add -seg_page_size option
-       * src/MachOWriterExecutable.hpp: use new page size info when laying out segments
-       * doc/man/man1/ld.1: update man page
-       
+       <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
 
-2008-09-24     Nick Kledzik    <kledzik@apple.com>
+2010-03-10    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/5798786> -arch_errors_fatal not working
-       * src/ld.cpp: check fOptions.errorOnOtherArchFiles()
-       * src/Options.cpp: turn -arch_errors_fatal into fOptions.errorOnOtherArchFiles()
+       * prevent possible crash in warning about can't export hidden symbols
 
+2010-03-10    Nick Kledzik    <kledzik@apple.com>
 
-2008-09-24     Nick Kledzik    <kledzik@apple.com>
+       * make sure split-info data is zero terminated
 
-       <rdar://problem/6161215> CrashTracer: [USER] 1 crash in ld at ld: 0x5ce02
-       * src/ld.cpp: abort if resolve() finds an unresolved reference, rather than allow a future crash
-       
+-------- tagged ld64-112
 
-2008-09-24     Nick Kledzik    <kledzik@apple.com>
+2010-03-09    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6157989> linker crashes linking X86-64 with -fwritable-strings
-       * src/MachOReaderRelocatable.hpp: handle unbound cfstring references
-       * unit-tests/test-cases/cfstring-coalesce: update test case
-       
+       * Never dead strip sections added with -sectcreate
+       * Added test case: unit-tests/test-cases/sectcreate-dead_strip
 
-2008-09-24     Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6213035> ld64: bl out of range (-17147704 max is +/-16M) on ppc
-       * src/MachOWriterExecutable.hpp: tweak branch island regions to be every 14MB instead of 15MB
-       
+-------- tagged ld64-111
 
-2008-09-24     Nick Kledzik    <kledzik@apple.com>
+2010-03-03    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/5907981> -filelist fails with comma in path
-       * src/Options.cpp: in loadFileList() first try without special comma meaning 
-       * unit-tests/test-cases/filelist/Makefile: update test case
-       
+       * Add support for "-arch arm -force_cpusubtype_ALL" to keep gcc building
 
-2008-09-23     Nick Kledzik    <kledzik@apple.com>
+2010-03-02    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6203068> nop not used when aligning functions in -r mode
-       * src/MachOWriterExecutable.hpp: change check for when to pad with nops to not test segment's name
-       
+       * Add some checking to the use of upward dylibs
 
-2008-09-23     Nick Kledzik    <kledzik@apple.com>
+-------- tagged ld64-110
 
-       <rdar://problem/6238329> "-pie can only be used when linking a main executable" should be a warning, not an error
-       *  src/Options.cpp: make -pie on a dylib or bundle be a warning instead of an error
-       
-       
-2008-09-23     Nick Kledzik    <kledzik@apple.com>
+2010-03-01    Nick Kledzik    <kledzik@apple.com>
 
-       * src/MachOReaderRelocatable.hpp: add warning if dwarf cannot be encoded as compact unwind
-       
+       * Don't coalesce cstrings across segments
 
-2008-09-18     Nick Kledzik    <kledzik@apple.com>
+2010-03-01    Nick Kledzik    <kledzik@apple.com>
 
-       * src/LTOReader.hpp: re-enable use of lto_codegen_debug_options()
+       * 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
 
-2008-09-16     Nick Kledzik    <kledzik@apple.com>
+2010-02-26    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6219054> ld does not always set S_CSTRING_LITERALS on __TEXT,__cstring
-       * src/MachOReaderRelocatable.hpp: add getContentType() to SymbolAtom
-       * src/MachOWriterExecutable.hpp: for x86_64 don't override named cstrings with LC* name
+       * Make sure building dyld results in a thread load command
        
+-------- tagged ld64-109
 
-2008-09-10     Nick Kledzik    <kledzik@apple.com>
-
-       * Options.cpp: add __crashreporter_info__ to communicate command line to crash reporter
-       * ld64.xcodeproj/project.pbxproj: leave local symbols in ld to provide better crash reports
-
+2010-02-26    Nick Kledzik    <kledzik@apple.com>
 
-2008-09-08     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
 
-       <rdar://problem/6126637> 161569 GCC 4.2 - breakpoints no longer work for a large number of functions
-       * src/MachOReaderRelocatable.hpp: support DW_FORM_strp out-of-line strings when parsing line table
+2010-02-26    Nick Kledzik    <kledzik@apple.com>
 
+       * Support pointer-diffs to zero sized atom in zero sized section 
 
-2008-09-02     Nick Kledzik    <kledzik@apple.com>
+2010-02-25    Nick Kledzik    <kledzik@apple.com>
 
-       * src/MachOReaderRelocatable.hpp: fix compact unwind personality for dyld and -slow_stubs
-       
+       * Add support for -r mode with ppc64 
 
-2008-08-29     Nick Kledzik    <kledzik@apple.com>
+2010-02-25    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6186838> -weak_library no longer forces uses to be weak_import
-       * src/MachOWriterExecutable.hpp: use fWeakImport on dylib to force proxy atoms into fWeakImportMap
-       * unit-tests/test-cases/weak_import-force: added test case
+       * 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
        
 
-2008-08-29     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/6061558> linker should order __DATA segment to reduce dyld dirtied pages
-       * src/Options.cpp: add fOrderData and support -no_data_order
-       * src/ld.cpp: modify tweakLayout() to sort atoms with relocations to start of __data section 
+2010-02-25    Nick Kledzik    <kledzik@apple.com>
 
+       * Handle old ppc .o files that have stubs to static functions
 
-2008-08-27     Nick Kledzik    <kledzik@apple.com>
+2010-02-25    Nick Kledzik    <kledzik@apple.com>
 
-       * src/Options.cpp:  back out <rdar://problem/6174493>
+       * Add basic ppc64 support
 
+2010-02-24    Nick Kledzik    <kledzik@apple.com>
 
------ Tagged ld64-87.5
+       * Range check TOC entries in archives
 
-2008-08-26     Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6174493> some projects show _Unwind_Resume coming from libSystem.B.dylib
-       * src/Options.cpp: swap any early symlinks to libSystem with libgcc_s
+2010-02-23    Nick Kledzik    <kledzik@apple.com>
 
+       * Fix spurious dylib re-export warnings that are just regular linkage cycles
 
------ Tagged ld64-87.4
 
-2008-08-25     Nick Kledzik    <kledzik@apple.com>
+2010-02-23    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6174493> some projects show _Unwind_Resume coming from libSystem.B.dylib
-       * src/Options.cpp: swap any early libSystem with libgcc_s
-       
+       * re-partition bits in mach_o::relocatable::Atom ivars to allow more functions per file
 
-2008-08-15     Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/5898326> Unable to build ppc debug builds (linker out of range error)
-       * src/MachOWriterExecutable.hpp: in addPPCBranchIslands() look ahead so large atoms don't push out branch islands
+2010-02-22    Nick Kledzik    <kledzik@apple.com>
 
+       * re-partition bits in mach_o::relocatable::Atom ivars to allow more fixups per function
        
------ Tagged ld64-87.3.1
-
-2008-09-08     Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6204202> i386 dylibs have incorrect personality pointers when put in dyld shared cache
-       * src/MachOWriterExecutable.hpp: in addCrossSegmentRef() handle kImageOffset32 to __IMPORT segment
+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
        
------ Tagged ld64-87.3
 
-2008-08-09     Nick Kledzik    <kledzik@apple.com>
+2010-02-22    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6125381> work around compiler gcc_except_table alignment
-       * src/ObjectFile.h: change getLSDA() to return a reference instead of an atom
-       * src/MachOReaderRelocatable.hpp: special case __eh_frame 64-bit pointer diff relocations
-       * src/MachOWriterExecutable.hpp: track lsda offset when creating __unwind_info section
-       * src/UnwindDump.cpp: log when LDSA content does not start with 0xFF
-
------ Tagged ld64-87.2
-
-2008-08-07     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/6131559> 10A141: libuwind falls back to dwarf and makes whole system super slow
-       * src/MachOWriterExecutable.hpp: Fix sign extension bug with x86_64::kPointerDiff24
-       * src/UnwindDump.cpp: warn about mangled LSDA entries when dumping unwind section
+       * Properly handle X86_64_RELOC_SUBTRACTOR with non-external target symbol
        
 
------ Tagged ld64-87.1
-
-2008-08-03     Nick Kledzik    <kledzik@apple.com>
+-------- tagged ld64-108
 
-       * src/LTOReader.hpp: Don't use lto_codegen_debug_options until newer libLTO.dylib is available
+2010-02-17    Nick Kledzik    <kledzik@apple.com>
 
-
------ Tagged ld64-87
-
-2008-07-21     Nick Kledzik    <kledzik@apple.com>
-
-       * src/Options.cpp: Always set fAutoOrderInitializers=false for dyld
+       * <rdar://problem/7658740> ER: Support upward dylib dependencies
+       * Add test case:  unit-tests/test-cases/dylib-upward
        
 
-2008-07-21     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOWriterExecutable.hpp: fix when regular vs compressed __unwind_info pages are generated
-       * src/UnwindDump.cpp: fix function name decoding in regular pages 
-       
-       
-2008-07-21     Nick Kledzik    <kledzik@apple.com>
+2010-02-17    Nick Kledzik    <kledzik@apple.com>
 
-       * ld64.xcodeproj/project.pbxproj: don't allow ld to build for x86_64 until libdtrace.dylib is available
+       * <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
        
 
-2008-07-18     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.hpp: don't crash if debug_line section has no line table
-
-
-2008-07-18     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5628149> Duplicate probe firings in Security.framework
-       * src/LTOReader.hpp: optimize() now returns atoms optimized away
-       * src/ObjectFile.h: optimize() should return if it did anything
-       * src/ArchiveReader.hpp: pass through optimize() result
-       * src/ld.cpp: rework dtrace probe processing as a new pass to prevent double counting
-
-
-2008-07-15     Nick Kledzik    <kledzik@apple.com>
+2010-02-17    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6061904> automatically order initializers to start of __TEXT
-       * src/Options.cpp: add -no_order_inits option
-       * src/MachOReaderRelocatable.hpp: merge __StaticInit into __text
-       * src/ObjectFile.h: add fAutoOrderInitializers
-       * src/ld.cpp: sort initializer to start of __text and terminators to end
-       * doc/man/man1/ld.1: add doc about -no_order_inits
-       * unit-tests/test-cases/init-order: add test case
+       * <rdar://problem/7625461> Wordsmith ld warning about missing directories
 
-2008-07-15     Nick Kledzik    <kledzik@apple.com>
-       
-       <rdar://problem/6073697> Only add LC_SEGMENT_SPLIT_INFO to dylibs that might be in the shared cache
-       * src/MachOWriterExecutable.hpp: re-layout load commands after split-seg data computed
-       * src/Options.cpp: non-public install name will disable split-seg load command
-       
-
-2008-07-14     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/6069861> ld -r for x86_64 is changing visibility of cstring constants
-       * src/MachOWriterExecutable.hpp: force x86_64 cstring labels to be local in -r mode
-       * unit-tests/test-cases/cstring-label: added test case
-       
 
-2008-07-11     Nick Kledzik    <kledzik@apple.com>
+2010-02-17    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6070190> ld not adding updating LC_SEGMENT_SPLIT_INFO with __unwind_info section
-       * src/MachOWriterExecutable.hpp: run createSplitSegContent() after __unwind_info section is created
+       * Fix -umbrella to work when umbrella is a dylib instead of a framework
+       * Add test case:  unit-tests/test-cases/umbrella-dylib
        
-2008-07-10     Nick Kledzik    <kledzik@apple.com>
-
-       * src/LTOReader.hpp: improve missing symbol error message
 
+-------- tagged ld64-107
 
-2008-07-09     Nick Kledzik    <kledzik@apple.com>
+2010-02-16    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6061558> linker should order __DATA segment to reduce dyld dirtied pages
-       * src/ld.cpp: first phase, order sections
+       * Fix bugs with -preload
 
 
-2008-07-08     Nick Kledzik    <kledzik@apple.com>
+2010-02-16    Nick Kledzik    <kledzik@apple.com>
 
-       * src/MachOReaderRelocatable.hpp: remove "coal" sections when creating a final linked image
+       * Fix dylib re-export cylce detection
 
 
-2008-07-08     Nick Kledzik    <kledzik@apple.com>
+2010-02-16    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6054476> ld: add support for mllvm LTO options
-       * src/Options.cpp: support -mllvm option
-       * src/LTOReader.hpp: call lto_codegen_debug_options() with -mllvm options
-       * src/ld.cpp: pass llvmOptions to optimize()
-       * src/Options.h: add fLLVMOptions
-       * src/ArchiveReader.hpp: add llvmOptions parameter to optimize()
-       * src/ObjectFile.h: add llvmOptions parameter to optimize()
-       * unit-tests/test-cases/lto-llvm-options: add test case
+       * <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
        
        
-2008-07-07     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/6054296> Linker fails with: 24-bit pointer diff out of range in unwind info in unwind info from...
-       * src/MachOWriterExecutable.hpp: fix when to fallback to uncompressed unwind info
-
+2010-02-15    Nick Kledzik    <kledzik@apple.com>
 
-2008-07-03     Nick Kledzik    <kledzik@apple.com>
+       * <rdar://problem/7398610> ld glibly removes /dev/null
 
-       <rdar://problem/6001472> ld crash with gcc-4.0 code that uses a zero sized array
-       * src/MachOReaderRelocatable.hpp: handle zero size atom in a zero sized section
        
+2010-02-15    Nick Kledzik    <kledzik@apple.com>
 
-2008-07-03     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
 
-       <rdar://problem/6016809> ld crashes when bad ppc relocs are found
-       * src/MachOReaderRelocatable.hpp: change all missing PAIR warnings to errors
-       
 
-2008-07-02     Nick Kledzik    <kledzik@apple.com>
+2010-02-15    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/5881324> when linking a kext the static linker should leave a pad in the headers to allow code signing
-       * src/MachOWriterExecutable.hpp: add padding for load commands in object files
-       * unit-tests/test-cases/code-signed-object-file: added test case
+       * <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
        
 
-2008-07-02     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/6048484> LC_SEGMENT_64 filesize incorrect for MH_OBJECT filetype
-       * src/MachOWriterExecutable.hpp: correctly set segment size info in object files
-       * unit-tests/test-cases/no-object-symbols: add test case
-
-
-2008-06-26     Nick Kledzik    <kledzik@apple.com>
+2010-02-15    Nick Kledzik    <kledzik@apple.com>
 
-       * ld64.xcodeproj/project.pbxproj: enable ld and rebase targets to build for x86_64
-       * src/rebase.cpp: remove unused fRelocBase field that was not 64-bit clean
-       * src/MachOReaderRelocatable.hpp: fix getEncodedP() to be 64-bit clean
+       * <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>
 
------ Tagged ld64-86.3
-
-2008-06-17     Nick Kledzik    <kledzik@apple.com>
-       
-       * src/ld.cpp: fix loadUndefines() to double check undefine symbol was not already loaded
-
-       
------ Tagged ld64-86.2
-       
-2008-06-14     Nick Kledzik    <kledzik@apple.com>
+       * Add support for LD_DYLD_PATH
 
-       * srd/ld.cpp: Add NULL check in getTentativesNames()
-       
-       
------ Tagged ld64-86.1
 
-2008-06-06     Nick Kledzik    <kledzik@apple.com>
+2010-02-15    Nick Kledzik    <kledzik@apple.com>
 
-       * src/MachOWriterExecutable.hpp: fix header padding calculation for dyld
+       * <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-86
+-------- tagged ld64-106
 
-2008-06-04     Nick Kledzik    <kledzik@apple.com>
+2010-02-12    Nick Kledzik    <kledzik@apple.com>
 
-       * src/LTOReader.hpp: if lto_codegen_add_module() fails, add explanation to error message
+       * <rdar://problem/7644673> Assertion failed: when class is translation unit scoped
+       * added test case unit-tests/test-cases/objc-visibility
        
 
-2008-06-04     Nick Kledzik    <kledzik@apple.com>
-
-       * src/ObjectFile.h: add deadAtoms parameter to optimize()
-       * src/ld.cpp: ditto
-       * src/ArchiveReader.hpp: ditto
-       * src/MachOReaderRelocatable.hpp: handle llvm use of 0x1B pointer encodings in CIEs
-       * src/LTOReader.hpp: make sure libLTO.dylib knows about any llvm symbol coalesced away
-       * unit-tests/test-cases/lto-weak-native-override: add test case
+2010-02-12    Nick Kledzik    <kledzik@apple.com>
 
+       * <rdar://problem/7644828> crash with missing crt?
 
-2008-06-04     Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/5935600> LTO : 176.gcc and 177.mesa build failure at -O4
-       * src/LTOReader.hpp: make sure internal is returned by getAtoms()
-       * unit-tests/test-cases/lto-archive-dylib: update test case
+2010-02-12    Nick Kledzik    <kledzik@apple.com>
 
+       * Suppress indirect symbol table in static executables
+       
 
-2008-06-03     Nick Kledzik    <kledzik@apple.com>
+2010-02-12    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/5894163> fix for 5613343 need to search for definitions for common symbols is broken
-       * src/ld.cpp: modify loadUndefines() to check for undefines in all files and tentative definitions but only in archives
-       * src/machochecker.cpp: check for undefine symbols and external symbols with same name
-       * unit-tests/test-cases/tentative-and-archive: update test case
+       * Rework CIE parsing to work with icc generated code
 
 
-2008-06-03     Nick Kledzik    <kledzik@apple.com>
+2010-02-11    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/5935237> linker produces wrong result for 16-bit call relocations
-       * src/MachOReaderRelocatable.hpp: properly parse i386 scattered relocs for word sized pc-rel vanilla
-       * src/MachOWriterExecutable.hpp: propery compute displacement for x86::kPCRel16
-       * unit-tests/test-cases/relocs-asm: update test case with callw instructions
-       
+       * Fix creation of debug notes
+       * Tweak unit-tests/test-cases/dwarf-debug-notes to match llvm symbol layout
 
-2008-06-03     Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/5905900> Building kext x86_64 with unexported symbols file causes linking problems
-       * src/MachOWriterExecutable.hpp: better check when creating undefined proxy atoms
-       * unit-tests/test-cases/unexported_symbols_list-r: added test case
-       
+2010-02-11    Nick Kledzik    <kledzik@apple.com>
 
-2008-06-02     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
 
-       <rdar://problem/5659338> S_CSTRING_LITERALS section type not preserved in executable
-       * src/ObjectFile.h: added ContentType
-       * src/MachOReaderRelocatable.hpp: set ContentType for anonymous string literals
-       * src/MachOWriterExecutable.hpp: set S_CSTRING_LITERALS if ContentType is kCStringType
-       * unit-tests/test-cases/cstring-custom-section: added test case
-       
 
-2008-06-02     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5980194> linker should produce __unwind_info section in final linked images
-       * src/ld.cpp: sort __unwind_info then __eh_frame section to end of __TEXT
-       * src/Architectures.hpp: add kImageOffset32 and kPointerDiff24
-       * src/ObjectFile.h: add compact unwind info support
-       * src/MachOReaderRelocatable.hpp: add compact unwind info support
-       * src/MachOFileAbstraction.hpp: add C++ wrappers for unwind section layout
-       * src/UnwindDump.cpp: new tool for dumping __unwind_info section
-       * src/MachOWriterExecutable.hpp: create __unwind_info section when needed
-       * src/ObjectDump.cpp: print unwind info
-       
+-------- tagged ld64-105
 
-2008-06-02     Nick Kledzik    <kledzik@apple.com>
+2010-02-11    Nick Kledzik    <kledzik@apple.com>
 
-       * unit-tests/test-cases/llvm-integration: split out some test cases
-       * unit-tests/test-cases/lto-preload-pie: added
-       * unit-tests/test-cases/lto-archive-dylib: added
+       * Use symbolic constants for bit field sizes
 
 
-2008-05-30     Nick Kledzik    <kledzik@apple.com>
+2010-02-10    Nick Kledzik    <kledzik@apple.com>
 
-       * unit-tests: fixes to build all tests with with gcc-4.2 on SnowLeopard
-       
+       * Handle out of order sections in .o files
 
-2008-05-30     Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/5536348> support -preload option to generate MH_PRELOAD binaries compatible with mtoc(1) and EFI
-       * src/ld.cpp: add entryPoint parameter to optimize()
-       * src/ArchiveReader.hpp: ditto
-       * src/ObjectFile.h: ditto
-       * src/LTOReader.hpp: use entryPoint parameter to optimize()
-       * src/Options.h: add kPreload and segment alignment
-       * src/Options.cpp: support -preload and -segalign
-       * src/MachOWriterExecutable.hpp: support kPreload and non-page aligned segments 
+-------- tagged ld64-104
 
+2010-02-10    Nick Kledzik    <kledzik@apple.com>
 
-2008-05-30     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
 
-       <rdar://problem/4431008> ld should warn if passed -r and also dylibs
-       * src/ld.cpp: check for spurious dylibs in Linker::addDylib()
 
+2010-02-10    Nick Kledzik    <kledzik@apple.com>
 
------ Tagged ld64-85.6
+       * Better warning messages about mismatched architectures
        
-2008-11-01     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/6254202> support increased branch range in Thumb-2
-       * src/MachOWriterExecutable.hpp: in fixUpReferenceFinal() support new longer branch range
-
 
-2008-11-01     Nick Kledzik    <kledzik@apple.com>
-       
-       <rdar://problem/6104368> ld warning: unknown option to -iphoneos_version_min, not 1.x or 2.x
-       * src/Options.cpp: In setIPhoneVersionMin() support 3.x
+2010-02-10    Nick Kledzik    <kledzik@apple.com>
 
-       
------ Tagged ld64-85.5
+       * Gracefully ignore if there are >8000 line info per function in debug info
 
-2008-09-17     Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6162415> vtable pointers can be missing thumb bit
-       * src/MachOWriterExecutable.hpp: Writer<arm>::fixUpReferenceFinal() OR in the 1 bit if the target
-               of a arm::kReadOnlyPointer is thumb.
+2010-02-10    Nick Kledzik    <kledzik@apple.com>
 
+       * Properly handle when regular definition is weak_imported
+       * Add unit-tests/test-cases/weak_import-local
 
------ Tagged ld64-85.4
 
-2008-08-11     Nick Kledzik    <kledzik@apple.com>
+2010-02-10    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6138961> ld should ignore LD_PREBIND when processing a static archive
-       * src/MachOWriterExecutable.hpp: in setImportNlist() never use N_PBUD for object files
+       * Don't try to coalesce zero length cstrings in mach-o parser.
        
------ Tagged ld64-85.3
 
-2008-07-14     Nick Kledzik    <kledzik@apple.com>
+2010-02-10    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/6060912> Prebinding busted in DTSB
-       * src/Options.cpp: check for libstdc++.6.0.[49] in seg_addr_table
+       * Add work around for llvm using L labels for backing string of CFString with -fwritable-strings
        
 
------ Tagged ld64-85.2
-
-2008-05-06     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5905889> ARM ld should take W bit off of maxprot for __TEXT segment
-       * src/MachOWriterExecutable.hpp: for iPhone always set maxprot to be initprot in all segments
+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
 
-2008-05-06     Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/5914343> encryptable images may not be signable
-       * src/MachOWriterExecutable.hpp: use minimum header padding when aligning __text section
-       
-
------ Tagged ld64-85 (Xcode 3.1)
-
-2008-04-29     Nick Kledzik    <kledzik@apple.com>
-
-       * ld64.xcodeproj/project.pbxproj: <llvm-c/lto.h> is moving from /usr/local/include to /Developer/usr/local/include
+2010-02-09    Nick Kledzik    <kledzik@apple.com>
 
+       * Fix file offset computation with large zero-fill sections
+        
 
-2008-04-29     Nick Kledzik    <kledzik@apple.com>
+2010-02-09    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/5829579> ld doesn't honor "rightmost" -syslibroot argument
-       * src/Options.cpp: if last -syslibroot is /, then ignore all syslibroots
+       * Force global 'l' to be hidden 
+       * Add test case with objc properties: unit-tests/test-cases/objc-properties
 
 
-2008-04-29     Nick Kledzik    <kledzik@apple.com>
-       
-       <rdar://problem/5866582> GLRendererFloat has bad __eh_frame section caused by mixing llvm-gcc and gcc object files
-       * src/MachOReaderRelocatable.hpp: make all atoms in __eh_frame section have 1-byte alignment
-       * src/MachOWriterExecutable.hpp: make __eh_frame section have pointer sized alignment
+-------- tagged ld64-103
 
+2010-02-04    Nick Kledzik    <kledzik@apple.com>
 
-2008-04-17     Nick Kledzik    <kledzik@apple.com>
+       * Temporarily change assert() to call exit(1) instead of abort() 
 
-       * src/MachOReaderRelocatable.hpp: better cpu subtype support
 
+2010-02-04    Nick Kledzik    <kledzik@apple.com>
 
-2008-04-14     Nick Kledzik    <kledzik@apple.com>
+       * Fix another case in -r mode where the vmsize was less that filesize
        
-       <rdar://problem/5733759> ld64 has bad ARM branch island check
-       * src/MachOWriterExecutable.hpp: in addBranchIslands() don't force large arm programs to fail
        
+2010-02-04    Nick Kledzik    <kledzik@apple.com>
 
-2008-04-10     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOWriterExecutable.hpp: fix stubs used with lazy dylibs
+       * Fix assert when generating GSYM stab debug notes
        
 
------ Tagged ld64-84.4
-
-2008-04-10     Nick Kledzik    <kledzik@apple.com>
+2010-02-04    Nick Kledzik    <kledzik@apple.com>
 
-       <rdar://problem/5847206> SPEC2000/eon built with -mdynamic-no-pic won't run
-       * src/Architectures.hpp: added arm::kReadOnlyPointer
-       * src/MachOReaderRelocatable.hpp: generate arm::kReadOnlyPointer
-       * src/MachOWriterExecutable.hpp: use arm::kReadOnlyPointer
-       * src/machochecker.cpp: allow MH_PIE bit
-       * unit-tests/test-cases/switch-jump-table: added test cases
-       
-
------ Tagged ld64-84.3
+       * Add SRCROOT to crash logs
 
-2008-04-09     Nick Kledzik    <kledzik@apple.com>
-       
-       <rdar://problem/5852023> -undefined dynamic_lookup busted
-       * src/ld.cpp: don't create proxy atom when scanning for dylib duplicates
-       * unit-tests/test-cases/tentative-and-archive: use -undefined dynamic_lookup
 
+2010-02-04    Nick Kledzik    <kledzik@apple.com>
 
------ Tagged ld64-84.2
+       * Remove architectureName() from InputFiles
 
-2008-04-04     Nick Kledzik    <kledzik@apple.com>
 
-       * src/ld.cpp: don't add .eh symbols to symbol table in -r mode
-       * unit-tests/test-cases/eh-coalescing-r: update to test out of order coalescing
-       
+-------- tagged ld64-102
 
------ Tagged ld64-84.1
+2010-02-03    Nick Kledzik    <kledzik@apple.com>
 
-2008-03-28     Nick Kledzik    <kledzik@apple.com>
+       * Add follow-on reference from symbol text atom to non-symboled text atom
 
-       <rdar://problem/5720961> ld should prefer architecture-specific variant over generic in fat object file
-       * src/Options.cpp: fully process -arch arguments into fArchitecture and fSubArchitecture
-       * src/ld.cpp: when -arch with a subtype is used, try to find the exact subtype from fat files
-       * unit-tests/test-cases/cpu-sub-types-preference: added test cases for arm and ppc
-       
 
------ Tagged ld64-84
+-------- tagged ld64-101
 
-2008-03-28     Nick Kledzik    <kledzik@apple.com>
+2010-01-29    Nick Kledzik    <kledzik@apple.com>
 
-       * src/LTOReader.hpp: don't print lto version, if lto is unavailable
+       * fix -alias symbols to be global by default
        
 
-2008-03-26     Nick Kledzik    <kledzik@apple.com>
+-------- tagged ld64-100
 
-       <rdar://problem/5575399> Add LD_WARN_COMMONS to BigBear builds
-       * src/Options.cpp: Add support for LD_WARN_FILE which copies all warnings to a side file
+2010-01-28    Nick Kledzik    <kledzik@apple.com>
        
-
-2008-03-26     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5797713> Need encryption tag in mach-o file
-       <rdar://problem/5811920> linker should adjust arm final linked images so __text is never on the same page as the load commands
-       * src/MachOFileAbstraction.hpp: add support for encryption_info_command
-       * src/Options.cpp: add support for LD_NO_ENCRYPT and -no_encryption
-       * src/MachOWriterExecutable.hpp: add EncryptionLoadCommandsAtom
-       * src/machochecker.cpp: validate LC_ENCRYPTION_INFO
+       * Merge new/refactored linker to trunk
        
-
-2008-03-25     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5712533> ld64 does not recognize LLVM bitcode archive files
-       * src/MachOReaderArchive.hpp: renamed to src/ArchiveReader.hpp
-       * src/ArchiveReader.hpp: sniff each member and instantiate correct reader
-       * src/ld.cpp: rename mach_o::archive::Reader to archive::Reader
-       * ld64.xcodeproj/project.pbxproj: rename MachOReaderArchive.hpp to ArchiveReader.hpp
-       * unit-tests/test-cases/llvm-integration: added test case
-
-
-2008-03-25     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5771658> ld64 should switch to new libLTO.dylib interface
-       <rdar://problem/5675690> Produce llvm bc file in 'ld -r' mode if all .o files are llvm bc
-       * src/LTOReader.hpp: rewrite from LLVMReader.hpp to use new lto_* C interface
-       * unit-tests/test-cases/llvm-integration: update and comment
-       * ld64.xcodeproj/project.pbxproj: update to lazy load libLTO.dylib 
-       * src/ld.cpp: rework and simplify Linker::optimize() 
-       * src/ObjectDump.cpp: Add -nm option
-       
-
-2008-03-25     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.cpp: Fix some .objc_class_name_ off by one problem
-       * src/MachOWriterExecutable.cpp: Fix some .objc_class_name_ off by one problem
-
-
-2008-03-24     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5814613> Xcode 3.1 breaks linkage of libgcj.9.dylib from gcc 4.3.0
-       * src/MachOWriterExecutable.cpp: Make sure all ivars in Writer are initialized.
-
-
-2008-03-21     Nick Kledzik    <kledzik@apple.com>
-
-       * src/Options.cpp: warn if -seg1addr value is not page aligned
-       
-
-2008-03-21     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5806437> Move ARM support outside of __OPEN_SOURCE__
-       * src/ld.cpp: remove __OPEN_SOURCE__ around arm support
-       * src/LLVMReader.hpp: remove __OPEN_SOURCE__ around arm support
-       * src/MachOReaderDylib.hpp: remove __OPEN_SOURCE__ around arm support
-       * src/ObjectFile.h: remove __OPEN_SOURCE__ around arm support
-       * src/MachOReaderRelocatable.hpp: remove __OPEN_SOURCE__ around arm support
-       * src/OpaqueSection.hpp: Cover arm support inside __OPEN_SOURCE__ macro check
-       * src/MachOWriterExecutable.hpp: remove __OPEN_SOURCE__ around arm support
-       * src/ObjectDump.cpp: remove __OPEN_SOURCE__ around arm support
-       * ld64.xcodeproj/project.pbxproj: remove ARM_SUPPORT from config.h
-       
-
------ Tagged ld64-83.2
-       
-2008-03-15     Nick Kledzik    <kledzik@apple.com>
-       
-       <rdar://problem/5801620> ld64-83 removes OBJC_CLASS_$ symbols from projects, causes catastrophic results
-       * src/Options.cpp: restore "case CPU_TYPE_ARM" in switch statement for .objc_class symbols in .exp files
-       * unit-tests/test-cases/objc-exported_symbols_list: added test case
-       
-       
------ Tagged ld64-83.1
-
-2008-03-14     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5800466> -iphone_version_min ==> -iphoneos_version_min
-       * src/Options.cpp: support -iphoneos_version_min as well
-       
-
------ Tagged ld64-83
-
-2008-03-10     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5791543> ld needs to strip iphone_version_min option if invoking ld_classic
-       * src/Options.cpp: suppress -iphone_version_min from being passed to ld_classic
-       
-
-2008-03-04     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4171253> ADOBE XCODE: Linker option to lazy load frameworks (cause dyld is too slow)
-       * src/MachOWriterExecutable.hpp: create lazy stubs and LC_LAZY_LOAD_DYLIB for lazy load dylibs
-       * src/Options.cpp: support -lazy-l, -lazy_library, and -lazy_framework
-       * src/MachOFileAbstraction.hpp: add LC_LAZY_LOAD_DYLIB and S_LAZY_DYLIB_SYMBOL_POINTERS until in cctools
-       * src/MachOReaderDylib.hpp: add isLazyLoadedDylib()
-       * src/ld.cpp: pass lazy helper atom to writer
-       * doc/man/man1/ld.1: document new options
-       * unit-tests/test-cases/lazy-dylib-objc: add test case
-       * unit-tests/test-cases/lazy-dylib: add test case
-       
-
------ Tagged ld64-82.7
-
-2008-03-07     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5787149> duplicate symbol literal-pointer@__OBJC@__message_refs@...
-       * src/MachOReaderRelocatable.hpp: AnonymousAtom from S_LITERAL_POINTERS section should be weak
-       * unit-tests/test-cases/objc-selector-coalescing: added test case
-
-       
------ Tagged ld64-82.6
-
-2008-03-04     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5779681> ld crashes building XsanFS for Snow Leopard Builds
-       * src/ld.cpp: add bool dylibsOnly parameter to addJustInTimeAtoms()
-       * unit-tests/test-cases/tentative-and-archive: added test case
-       
-2008-03-04     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5775822> ld64 should not force building with gcc 4.0
-       * ld64.xcodeproj/project.pbxproj: change rules to use "system" compiler instead of 4.0
-       
-
-2008-02-29     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5774730> Simulator frameworks are being build split-seg and not prebound
-       * src/Options.cpp: only splitseg if prebound
-
-
-2008-02-29     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5774231> Linker should not make GSYM debug note for .objc_category_* symbols
-       * src/ld.cpp: suppress GSYM debug notes for absolute symbols
-       * unit-tests/test-cases/objc-category-debug-notes: added test case
-
-
-2008-02-29     Nick Kledzik    <kledzik@apple.com>
-
-    <rdar://problem/5768970> non-ASCII CFString support is broken
-    * src/MachOReaderRelocatable.hpp: only name and coalesce cfstring constants if they use a __cstring
-    * unit-tests/test-cases/cfstring-utf16: add test case
-
-
-2008-02-25     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5366363> ld -r -x 
-       * doc/man/man1/ld.1: update man page to explain -r -x produces auto-stripped labels
-
-
------ Tagged ld64-82.5
-
-2008-02-12     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5738023> x86_64: -stack_size failure when large __bss is used
-       * src/ld.cpp: only move section already in __DATA segment to new __huge section 
-       * unit-tests/test-cases/stack_size_no_addr: updated test case to add large bss section
-       
-
------ Tagged ld64-82.4
-
-2008-02-06     Nick Kledzik    <kledzik@apple.com>
-       
-       <rdar://problem/5726215> comdat warnings with ld -r of C++ .o files
-       * unit-tests/test-cases/eh-coalescing-r: added test case
-       * src/ld.cpp: in ld -r mode don't warn about if .eh symbols are not static
-       
-
-2008-02-06     Devang Patel    <dpatel@apple.com>
-
-       <rdar://problem/5724990> LTO of Bom framework with -dead_strip causes ld(1) crash
-       * src/LLVMReader.hpp: Check fAtom while determining LLVMReference target binding.
-       * unit-tests/test-cases/llvm-integration/Makefile: Add new test case.
-       * unit-tests/test-cases/llvm-integration/a15.c: New.
-       * unit-tests/test-cases/llvm-integration/b15.c: New.
-       * unit-tests/test-cases/llvm-integration/c15.c: New.
-       
-2008-02-05     Nick Kledzik    <kledzik@apple.com>
-
-       * src/ld.cpp: fix for -arch ppc -mdynamic-no-pic -pie so PPC_RELOC_HA16 reloc is used
-       
------ Tagged ld64-82.3
-       
-2008-02-04     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5721186> ld doesn't seem to understand $ld$add$os... and $ld$hide$os... for 10.6 moves
-       * src/ObjectFile.h: add 10.6
-       * src/Options.cpp: add 10.6 support
-       * src/MachOReaderDylib.hpp: recognize $os10.6$
-       
-
------ Tagged ld64-82.2
-
-2008-01-30     Devang Patel    <dpatel@apple.com>
-
-       <rdar://problem/5714833> Can't build 64-bit Intel binaries with LTO
-       <rdar://problem/5714787> ld64 fails to build with llvm-gcc-4.2
-       * src/LLVMReader.hpp: Fix character count typo in strncmp call.
-       Use const char * to initialize temp. string.
-       * ld64.xcodeproj/project.pbxproj: use $(DEVELOPER_DIR) in header search construction
-       instead of hard coding /Developer.
-       
------ Tagged ld64-82.1
-
-2008-01-23     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.hpp: don't bus error if S_LITERAL_POINTERS is missing relocs
-       
-
-2008-01-22     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5695496> ld uses 32-bits in some places to hold addresses when parsing 64-bit mach-o files
-       * src/MachOReaderRelocatable.hpp: use AddrToAtomMap type that switch address to 64-bits for 64-bit archs
-       * src/MachOWriterExecutable.hpp: verify BR14 does not overflow for external relocs
-       * unit-tests/test-cases/relocs-c: update test case to slide addresses to verify x86_64 .o files
-
-       
------ Tagged ld64-82
-       
-2008-01-18     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5694612> Bad grammar used in ld warning: cannot exported hidden symbol
-       * src/ld.cpp: fix typo in warning string
-       
-
-2008-01-16     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5565074> Bundle Loader does not work anymore when loader is a bundle
-       <rdar://problem/5590203> ld warns of incorrect architecture when linking a bundle to a bundle
-       * src/MachOReaderDylib.hpp: support linking against bundles via -bundle_loader. Clean up error messages
-       * unit-tests/test-cases/bundle_loader: update test case
-               
-       
-2008-01-16     Nick Kledzik    <kledzik@apple.com>
-       
-       <rdar://problem/5366363> ld -r -x creates debug notes (stabs) when it should not with -x (keep only global symbols)
-       * src/Options.cpp: in reconfigureDefaults() if -r and -x then -S
-       
-
-2008-01-16     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5566068> if ld crashes while writing output file, it should delete the half written file
-       * src/MachOWriterExecutable.hpp: wrap open/write/close in try block and add signal handlers all to delete
-       output file on failure.
-       
-
-2008-01-16     Devang Patel    <dpatel@apple.com>
-
-       * src/LLVMReader.hpp: Use __gnu_cxx::hash_map instead of hash supported by LLVM.
-
-
-2008-01-16     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5593537> GC-supported library can't be linked into GC-required executable
-       * src/ld.cpp: loosen constraint that all objc code must be compiled with same GC settings and
-       allow gc-compatible code to be linked into anything.
-       * unit-tests/test-cases/objc-gc-checks: update test case
-
-
-2008-01-15     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5687976> no debug notes for custom named data
-       * src/ld.cpp: in synthesizeDebugNotes() check getSymbolTableInclusion() instead of for leading underscore
-       * unit-tests/test-cases/dwarf-debug-notes: update test case
-       
------ Tagged ld64-81.5
-
-2008-01-14     Devang Patel    <dpatel@apple.com>
-
-       <rdar://problem/5683813> llvm-gcc-4.2 fails to build Sqlite 3.5.4 with -O4
-       * src/LLVMReader.hpp: Resolve proxy references. Collect new unbounded references 
-       after optimization.
-       * src/ld.cpp: Resolve additional unbounded references after optimization.
-       
-
-2008-01-14     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5655246> PPC Leopard (Xcode 3.0) linker ld gets "Bus error" sometimes
-       * src/MachOReaderRelocatable.hpp: use same code as x86 to parse ppc and arm sect-diff relocs
-       * src/MachOWriterExecutable.hpp:  use same code as x86 to write ppc and arm sect-diff relocs
-       
-
-2008-01-11     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5637618> PPC Leopard (Xcode 3.0) linker ld reports "unknown scattered relocation type 4"
-       * src/MachOReaderRelocatable.hpp: add PPC_RELOC_HI16 to scattered reloc parsing
-       * unit-tests/test-cases/relocs-asm/relocs-asm.s: added tests for scattered hi/lo instructions
-       
-
-2008-01-11     Nick Kledzik    <kledzik@apple.com>
-
-       * doc/man/man1/ld.1: add doc for -no_implicit_dylibs, -read_only_stubs, -slow_stubs, -interposable_list
-       
-       
-2008-01-11     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4800212> ld64(1) man page uses ambiguous term "suffix"
-       * doc/man/man1/ld.1: make meaning of "suffix" more explicit
-       
-
-2008-01-11     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5633081> Obj-C Symbols in Leopard Can't Be Weak Linked
-       * src/MachOWriterExecutable.hpp: set weak and lazy attributes on dummy .objc_class_name undefines
-        to dylibs to support Mac OS X 10.3.x dyld
-        
-
-2008-01-11     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5669751> Unknown error with linker (dyld: unknown external relocation type)
-       * src/ld.cpp: fix crash when SO stabs are not balanced
-       
-
-2008-01-11     Devang Patel    <dpatel@apple.com>
-
-       <rdar://problem/5667433> LTO does not work if expected output is a dynamic library
-       * src/LLVMReader.hpp: Supply arguments describing output kind to optimizer. Communicate
-       visibility info.
-
-2000-01-10     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5680988> __cls_refs section is losing S_LITERAL_POINTERS section type
-       * src/MachOWriterExecutable.hpp: special case __cls_refs section 
-       * unit-tests/test-cases/objc-literal-pointers: add test case
-
-
-2008-01-03     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5667688> wrong EH information might be used
-       Created new kGroupSubordinate reference kind to model group comdat.  The "signature" atom
-       has kGroupSubordinate references to the other atoms in the group.  If the signature atom
-       is coalesced away, the linker follows kGroupSubordinate references and throws away the
-       other members of the group.
-       * unit-tests/test-cases/eh-coalescing: added test case
-       * src/ld.cpp: added markDead() and use propagate to subordinates
-       * src/Architectures.hpp: added kGroupSubordinate
-       * src/MachOReaderRelocatable.hpp: add kGroupSubordinate reference from a function to its .eh atom
-         and if used, from .eh atom to its LSDA atom.
-       * src/MachOWriterExecutable.hpp: handle kGroupSubordinate like kNoFixUp
-
------ Tagged ld64-81.4.1
-
-2007-12-19     Devang Patel    <dpatel@apple.com>
-
-       * src/LLVMReader.hpp: Add LLVM_LTO_VERSION #ifdef check.
-       
-2007-12-19     Devang Patel    <dpatel@apple.com>
-
-       * src/LLVMReader.hpp: Add fOptimizer NULL check before calling printVersion().
-       
-2007-12-19     Devang Patel    <dpatel@apple.com>
-
-       <rdar://problem/5655956> print LLVM LTO version number in verbose mode
-       * src/LLVMReader.hpp: Add printLLVMVersion() to print llvm version string in verbose mode.
-       * src/Options.cpp: Use printLLVMVersion() in verbose mode.
-
-2007-12-19     Devang Patel    <dpatel@apple.com>
-
-       <rdar://problem/5655956> print LLVM LTO version number in verbose mode
-       * src/Options.h: Add verbose() method to check fVerbose flag.
-       * src/LLVMReader.hpp: Print LLVM version string in verbose mode.
-       
------ Tagged ld64-81.4
-
-2007-12-18     Devang Patel    <dpatel@apple.com>
-
-       * src/LLVMReader.hpp: Invalidate input architecture when optimizer is not available.
-
------ Tagged ld64-81.3
-
-2007-12-17     Nick Kledzik    <kledzik@apple.com>
-
-       * ld64.xcodeproj/project.pbxproj: remove extraneous header search paths
-       
-
-2007-12-17     Devang Patel    <dpatel@apple.com>
-
-       * src/LLVMReader.hpp: Do not throw exception if LLVMReader is not able to
-       dlopen LTO library. Instead just flag input file as an invalid LLVM bitcode file.
-
-
-2007-12-14     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5645908> gcc DejaGnu failure: gcc.dg/20020312-2.c (test for excess errors) (-fstack-protector-all)
-       * src/MachOWriterExecutable.hpp: fix Writer<x86>::generatesExternalTextReloc() to allow text relocs
-       * unit-tests/test-cases/read-only-relocs: updated test case to link a dynamic main executable compiled with -static
-
-
-2007-12-14     Devang Patel    <dpatel@apple.com>
-
-  <rdar://problem/5648438> Enable Link Time Optimization in Opal
-  * src/LLVMReader.hpp: Locate LLVMlto.dylib relative to ld location in Developer folder.
-  * ld64.xcodeproj/project.pbxproj: Add {DEVELOPER_DIR}/usr/include in header search path.
-  * unit-tests/run-all-unit-tests: Set DYLD_FALLBACK_LIBRARY_PATH to find LLVMlto.dylib during unit testing.
-  * unit-tests/testcases/llvm-integration/Makefile: Point LLVMGCC and LLVMGXX to llvm-gcc-4.2 in Developer folder during unit testing.
-  
-  
-2007-12-13     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5645446> SWB: failures due to ld: pointer in read-only segment not allowed in slidable image, used in ...
-       * src/MachOReaderRelocatable.hpp: in Reader<x86>::addRelocReference() handle weak pc-rel 32-bit vanilla relocs properly
-       
------ Tagged ld64-81.2 
-
-
-
-2007-12-07     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5615298> support 8-bit relocations for i386
-       * src/Architectures.hpp: add kPCRel8
-       * src/MachOReaderRelocatable.hpp: support 8-bit pc-rel relocations for intel
-       * src/MachOWriterExecutable.hpp: support 8-bit pc-rel relocations for intel
-       * unit-tests/test-cases/relocs-asm: add test cases
-
-
------ Tagged ld64-81.1 
-
-2007-12-06     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderDylib.hpp: rework cycle detection to remove some false positives
-       
-
-2007-12-05     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5628149> Duplicate probe firings in Security.framework
-       * src/ld.cpp: check dtrace probe sites are not in fDeadAtoms before using
-       * unit-tests/test-cases/dtrace-static-probes-coalescing: add test case
-       
-
-2007-12-05     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.hpp: fix CFString coalescing to work with -fwritable-strings
-       * unit-tests/test-cases/cfstring-coalesce: add -fwritable-strings to test case
-
-
------ Tagged ld64-81   
-
-2007-11-15     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4196067> ld64 should support runtime text relocations
-       * src/MachOWriterExecutable.hpp: add generatesLocalTextReloc() and generatesExternalTextReloc()
-       * src/Options.cpp: process -read_only_relocs option
-       * src/Options.h: add allowTextRelocs() and warnAboutTextRelocs()
-       * src/MachOReaderRelocatable.hpp: add hasLongBranchStubs()
-       * src/machochecker.cpp: allow relocs in read only segments, if section flags are set
-       * unit-tests/test-cases/read-only-relocs: update test case
-
-
-2007-11-08    Devang Patel     <dpatel@apple.com>
-
-       * ld64.xcodeproj/project.pbxproj: add new build phase "build configure.h" for
-       ld target.
-       * src/ld.cpp: Include "configure.h"
-
-
------ Tagged ld64-80.11
-
-2008-02-12     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5741312> Wrong section name for objc info for ARM when OBJC2 is used
-       * src/MachOWriterExecutable.hpp: switch segment/section name for ARM objc2 image info
-
------ Tagged ld64-80.10
-       
-2008-02-11     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5733578> ld64 does not support -aspen_version_min 2.0
-       * src/Options.cpp: allow 2.x for -aspen_version_min
-       
-
-2008-02-11     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5733575> ld_classic: unknown flag: -aspen_version_min
-       * src/Options.cpp: change -aspen_version_min x.x to -macosx_version_min 10.5 when invoking ld_classic
-       
-
------ Tagged ld64-80.9 
-
-2008-01-29     Nick Kledzik    <kledzik@apple.com>
-       
-       <rdar://problem/5713054> -iphone_version_min ==> -aspen_version_min
-       * src/Options.cpp: support -aspen_version_min
-       
-
------ Tagged ld64-80.8 
-
-2008-01-10     Nick Kledzik    <kledzik@apple.com>
-       
-       * src/Options.cpp: support transition to new objc ABI for ARM by allowing old .objc_class_name_* 
-       style names in export files and map them to new _OBJC_CLASS_$_ style names.
-       
-
------ Tagged ld64-80.7 
-
-2008-01-02     Nick Kledzik    <kledzik@apple.com>
-       
-       <rdar://problem/5572168> BigBear5A18 isn't fully prebound
-       * src/Options.cpp: make fNeedsModuleTable true for arm
-
------ Tagged ld64-80.6 
-
-2007-11-30     Nick Kledzik    <kledzik@apple.com>
-       
-       <rdar://problem/5620976> -iphone_version_min
-       * src/Options.cpp: handle -iphone_version_min option
-
-
------ Tagged ld64-80.5 
-
-2007-11-26     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5601142> need to special case some dylibs in seg_addr_table
-       * src/Options.cpp: retry seg_add_table lookup for a couple of unusual dylibs
-       
-       
------ Tagged ld64-80.4 
-
-2007-11-06     Nick Kledzik    <kledzik@apple.com>
-       
-       * src/MachOReaderRelocatable.hpp: fix parsing of external and scattered thumb branch22 relocs
-       * unit-tests/test-cases/thumb-blx: add test case to keep blx issues from coming back
-
------ Tagged ld64-80.3 
-       
-2007-11-03     Nick Kledzik    <kledzik@apple.com>
-       
-       * src/MachOReaderRelocatable.hpp: remove recalc of dstAddr which could cause thumb branches to be +2
-       * src/MachOWriterExecutable.hpp: remove incorrect test for relocateableExternal
-       
------ Tagged ld64-80.2
-
-2007-11-01     Nick Kledzik    <kledzik@apple.com>
-
-       * src/ld.cpp: hack my own prototype for log2() until math.h is cleaned up
-       
-       
------ Tagged ld64-80.1
-
-2007-11-01     Nick Kledzik    <kledzik@apple.com>
-
-       * ld64.xcodeproj/project.pbxproj: add HEADER_SEARCH_PATHS for cross builds
-       * src/ld.cpp: temporarily disable LLVM_SUPPORT
-       * src/MachOWriterExecutable.hpp: Don't use CC_MD5() directly
-
-
-2007-10-26     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5556038> Cannot build with libm_static.a statically linked
-       * src/MachOWriterExecutable.hpp: Fix makesExternalRelocatableReference() for -r -d case
-       * unit-tests/test-cases/tentative-to-real-hidden: add test case
-
-
------ Tagged ld64-80
-
-2007-10-24     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4222696> linker should probably warn about trying to export a hidden symbol
-       * src/ld.cpp: if using -exported_symbols_list check each hidden atom as it is added to symbol table
-       * src/Options.h,.cpp: add hasExportMaskList()
-       * unit-tests/test-cases/exported_symbols_list-hidden: added test case
-
-
-2007-10-24     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOWriterExecutable.hpp: keep old style dtrace probes externel for kernel builds
-       
-
-2007-10-23     Nick Kledzik    <kledzik@apple.com>
-       
-       <rdar://problem/4556199> unify error and warning messages
-       <rdar://problem/5546450> -w should suppress warnings
-       * src/ld.cpp: use warning() function
-       * src/Options.h: remove emitWarnings()
-       * src/MachOReaderDylib.hpp: use warning() function
-       * src/MachOReaderRelocatable.hpp: use warning() function
-       * src/Options.cpp: use and implement warning()
-       * src/MachOWriterExecutable.hpp: use warning() function
-       * unit-tests/test-cases/visibility-warning: verify -w suppresses warnings
-
-
-2007-10-23     Devang Patel    <dpatel@apple.com>
-
-       * src/ld.cpp: Cover arm support inside __OPEN_SOURCE__ macro check.
-       * src/LLVMReader.hpp: Cover arm support inside __OPEN_SOURCE__ macro check.
-       * src/MachOReaderDylib.hpp: Cover arm support inside __OPEN_SOURCE__ macro check.
-       * src/ObjectFile.h: Cover arm support inside __OPEN_SOURCE__ macro check.
-       * src/MachOReaderRelocatable.hpp: Cover arm support inside __OPEN_SOURCE__ macro check.
-       * src/OpaqueSection.hpp: Cover arm support inside __OPEN_SOURCE__ macro check
-       * src/MachOWriterExecutable.hpp: Cover arm support inside __OPEN_SOURCE__ macro check.
-       * src/ObjectDump.cpp: Cover arm support inside __OPEN_SOURCE__ macro check.
-       
-
-2007-10-22     Nick Kledzik    <kledzik@apple.com>
-
-       * src/Options.cpp: add support for LD_DEAD_STRIP and LD_WARN_COMMONS
-       * src/MachOReaderRelocatable.hpp: fix problem with -dead_strip of ObjC literal pointers
-
-
-2007-10-22     Nick Kledzik    <kledzik@apple.com>
-
-       * src/Options.cpp: have -static arm code link with ld_classic (for now)
-       
-
-2007-10-22     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5396826> Recognize all arm architectures
-       * src/MachOReaderRelocatable.hpp: add support for all ARM sub-types
-       * unit-tests/test-cases/cpu-sub-types: add test cases for all combinations of ARM sub-types
-
-
-2007-10-19     Nick Kledzik    <kledzik@apple.com>
-
-       * src/*: merge in arm support
-       * unit-tests/test-cases/*: fix to work for arm and thumb
-
------ Tagged ld64-79
-
-2007-10-16     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOWriterExecutable.hpp: if -r mode, always set custom alignment (SET_COMM_ALIGN) on common symbols
-       * unit-tests/test-cases/visibility-warning-dylib-v-archive/Makefile: fix warning
-       * unit-tests/test-cases/static-executable/Makefile: fix spurious failure
-
-
-2007-10-16     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOWriterExecutable.hpp: fix edge case in branch island generation
-
-
-2007-10-12     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5323449> Add option to create old, slow stubs for i386
-       * src/ObjectFile.h/.cpp: support -read_only_stubs
-       * src/MachOWriterExecutable.hpp: enhance StubAtom<x86> to support old style __symbol_stub/__la_symbol_ptr stubs
-       * unit-tests/test-cases/slow-x86-stubs: add test case
-
-
-2007-10-12     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5427952> ld64's re-export cycle detection logic prevents use of X11 libGL on Leopard
-       * src/Options.cpp: in findFileUsingPaths() don't search for embedded dylibs
-       * unit-tests/test-cases/indirect-path-search/Makefile: added case for a dylib embedded in a framework
-
-
-2007-10-11     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5451987> add option to disable implicit load commands for indirectly used public dylibs
-       * src/Options.cpp: add support for -no_implicit_dylibs
-       * src/ObjectFile.h: add fImplicitlyLinkPublicDylibs
-       * src/MachOReaderDylib.hpp: test fImplicitlyLinkPublicDylibs before hoisting an implicitly linked dylib
-       * unit-tests/test-cases/implicit_dylib: add test case
-
-
-2007-10-11     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5254413> -interposable_list
-       * src/Options.h/cpp: Add fInterposeList and fInterposeMode to support -interposable_list
-       * src/MachOWriterExecutable.hpp: pass symbol name to fOptions.interposable()
-       * unit-tests/test-cases/interposable_list: add test case
-
-
-2007-10-10     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5529626> If only weak_import symbols are used, linker should use LD_LOAD_WEAK_DYLIB
-       * src/MachOWriterExecutable.hpp: automatically use LC_LOAD_WEAK_DYLIB if all symbols used from a dylib are weak_import
-       * unit-tests/test-cases/weak_dylib: added test case
-
-
-2007-10-10     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5504954> linker does not error when dylib ordinal exceeds 250
-       * src/MachOWriterExecutable.hpp: error out if ordinals exceed max allowed
-       
-
-2007-10-10     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4067110> overriding 'operator new' or 'operator delete' fails if no weak symbols are present
-       * src/ld.cpp: at end of checkUndefines() search dylibs for weak versions of any global external symbols 
-       * src/ObjectFile.h: add hasWeakExternals() method to Reader
-       * src/MachOReaderDylib.hpp: implement hasWeakExternals() method in Reader
-       * src/ExecutableFile.h: add overridesDylibWeakDefines parameter to write()
-       * src/MachOWriterExecutable.hpp: use overridesDylibWeakDefines parameter to write()
-       * unit-tests/test-cases/operator-new: add test case
-       
-
-2007-10-05     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5048861> No warning about tentative definition conflicting with dylib definition
-       <rdar://problem/5132652> .comm variables in shared library, worked with XCode 2.4.1, broken with XCode 3?
-       * src/ld.cpp: at end of checkUndefines() verify if any remaining commons conflict with dylibs
-       * doc/man/man1/ld.1: document -commons and -warn_commons options
-       * unit-tests/test-cases/tentative-and-dylib: added test case
-
-
-2007-10-05     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5346331> NS/CFString constants are not dead strippable
-       * src/MachOReaderRelocatable.hpp: break up __cfstring section into one atom per cfstring, make them coalesable
-       * unit-tests/test-cases/cfstring-coalesce: added test case
-
-
-2007-10-05     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5524973> Dead stripping + exported symbols list using wildcards doesn't seem to do the right thing
-       * src/Options.cpp/h: add hasWildCardExportRestrictList()
-       * src/ld.cpp: if dead stripping code and have wildcard exports, add all global atoms matching wildcards as roots
-       * unit-tests/test-cases/exported-symbols-wildcards-dead_strip: added test case
-
-
-2007-10-04     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5433882> ld shouldn't search /Network/Library/Frameworks by default
-       * src/Options.cpp: remove /Network/Library/Frameworks/ from default search path
-       * doc/man/man1/ld.1: document the change
-       
-
-2007-10-04     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5341567> all binaries should get LD_UUID load commands, not just those with DWARF symbols
-       * src/ld.cpp: default fCreateUUID to be true for non object file output types
-       * unit-tests/test-cases/no-uuid/Makefile: update test case to match new rules
-
-
------ Tagged ld64-78
-
-2007-09-27     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5476313> range check load commands
-       * src/MachOReaderDylib.hpp: check that load commands all fit in load command size from header
-       * src/MachOReaderRelocatable.hpp: check that load commands all fit in load command size from header
-
-
-2007-09-27     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5433355> Xc8M2540a: ld64 crashes when linking Pascal program
-       * src/ld.cpp: fix findAtomAndOffset() to handle where there are no function atoms 
-
-
-2007-09-27     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5241179> ADOBE Xcode 3: ld -dead_strip does not work with -init from an archive
-       * src/ld.cpp: add bool parameter to entryPoint() so -init atom not looked for too soon
-       * unit-tests/test-cases/dead_strip-init-archive: added test case
-       
-
-2007-09-26     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5459546> Spurious link warnings for inline members of C++ template classes
-       * src/ld.cpp: check definition kinds before warning about visibility mismatches
-       * unit-tests/test-cases/visibility-warning: added test case
-       
-
-2007-09-26     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5394172> an empty .o file with zero load commands will crash linker
-       * src/MachOReaderRelocatable.hpp: have Reader constructor return early of no load commands
-       * unit-tests/test-cases/empty-object: added test case
-       
-       
-2007-09-26     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5453384> 9a527: ppc64 branch islands fail with 4GB pagezeo
-       * src/MachOWriterExecutable.hpp: start range calculations at start of __text not at zero.
-       
-
------ Tagged ld64-77 (Xcode 3.0)
-
-2007-07-23     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5351380> Kernel is linked with some global symbols unsorted
-       * src/MachOWriterExecutable.hpp: Add NListNameSorter to allow global atoms and extra labels to be sorted
-
-
-2007-07-20     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5254468> Can't do objc_msgSendSuper dispatches after loading a Fix&Continue bundle
-       * src/MachOWriterExecutable.hpp: when calculating what kind of reloc to use, never use an 
-         external reloc to reference 32-bit ObjC symbols.
-
-
-2007-07-20     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5349847> Runtime crash with ICC math library on Leopard
-       * src/MachOReaderRelocatable.hpp: detect if section starts with a symbol that is not 
-         aligned to section and correct it.
-
-
------ Tagged ld64-76
-
-2007-06-29     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5303718> export hiding does not work for frameworks
-       * src/MachOReaderDylib.hpp: fix checks in isPublicLocation()
-       * unit-tests/test-cases/symbol-moving: update to test frameworks as well as dylibs
-
-
-2007-06-27     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5299907> linker should use undefines from flat dylibs when linking a main flat
-       * src/ObjectFile.h: added fLinkingMainExecutable
-       * src/Options.cpp: set up fLinkingMainExecutable
-       * src/MachOReaderDylib.hpp: when linking a main executable for flat namespace, the reader for
-               any loaded flat namespace dylib will have a new atoms that has references to all undefined
-               symbols in the dylib
-       * unit-tests/test-cases/flat-indirect-undefines: added test case
-       * doc/man/man1/ld.1: update man page to describe when dylib undefines are used
-       
-
-2007-06-27     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5277857> OpenGL.framework and X11 both have a libGL.dylib which can cause ld to segfault if both are found
-       * src/MachOReaderDylib.hpp: add assertNoReExportCycles() method
-       * unit-tests/test-cases/dylib-re-export-cycle: added test case
-
-
-2007-06-27     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5286462> ld64 has slightly different warning message formats than the old ld
-       * src/ld.cpp: standardize all warning messages to start with "ld: warning"
-       * src/MachOWriterExecutable.hpp: ditto
-       * src/MachOReaderRelocatable.hpp: ditto
-       * src/MachOReaderDylib.hpp:ditto
-
-
-2007-06-26     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5297034> -dead_strip can cause duplicate external commons
-       * src/ld.cpp: don't use discarded coalesced global atoms as dead strip roots
-       * src/machochecker.cpp: error if duplicate external symbols
-       * unit-tests/test-cases/commons-coalesced-dead_strip: added test case
-       
-
-2007-06-26     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4135857> update man page that linker does not search indirect libraries with two-level namespace
-       * doc/man/man1/ld.1: add new "Indirect dynamic libraries" section to man page
-       
-
-2007-06-26     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5285473> Xc9A466: Exports file cannot use Mac line ends
-       * src/Options.cpp: check for \r or \n when parsing .exp files
-       * unit-tests/test-cases/exported_symbols_list-eol: added test case
-       
-
------ Tagged ld64-75
-
-2007-05-31     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4607755> Simplier, generalized way to re-export dylibs: LC_REEXPORT_DYLIB
-       * src/MachOWriterExecutable.hpp: Use LC_REEXPORT_DYLIB when targetting 10.5
-
-
------ Tagged ld64-74.5
-
-2007-05-31     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5241902> set OSO timestamp to zero for when building in buildit
-       * src/ld.cpp: check for RC_RELEASE and if exists set all OSO timestamps to zero
-       
-
-2007-05-30     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5224676> BUILD_STABS now causes ld of xnu to bus error
-       * src/ld.cpp: Change || to && in collectStabs()
-
-
------ Tagged ld64-74.4
-
-2007-05-18     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5211667> static probes don't work with libraries in dyld shared cache
-       *  src/OpaqueSection.hpp: the __TEXT segment is executable
-
-
------ Tagged ld64-74.3
-
-2007-05-16     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5201463> ppc: linker adds stubs to cstring references
-       * src/MachOWriterExecutable.hpp: update ppc stubableReference() to only allow high/low references
-               to be stubed if they reference a symbol in some other dylib.
-       * unit-tests/test-cases/stub-generation: added test case
-       
-
-2007-05-16     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5008421> ppc64: need to make LOCAL indirect symbol table entry for now local symbol
-       * src/MachOWriterExecutable.hpp: factored local tests into indirectSymbolIsLocal()
-       * unit-tests/test-cases/non-lazy-r: added test case
-       
-
-2007-05-15     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5198807> ld64 drops fix&continue bit in __OBJC, __image_info.
-       * src/MachOReaderRelocatable.hpp: implement objcReplacementClasses()
-       
-
-2007-05-15     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5066152> support __image_info in __DATA segment for 64-bits
-       * src/MachOReaderRelocatable.hpp: use strncmp() for __objc_imageinfo since it is 16 bytes long
-       * src/MachOWriterExecutable.hpp: specialize segment/section names for synthesized objc image info section
-
-
-2007-05-15     Nick Kledzik    <kledzik@apple.com>
-
-       * unit-tests/include/common.makefile: set COMPILER_PATH so harness works with latest compiler
-
-
------ Tagged ld64-74.2
-
-2007-05-11     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5195447> ld64-74.1 breaks libstdc++ DejaGnu test (G5 only)
-       * src/MachOWriterExecutable.hpp: don't stub a reference if the target offset is non-zero
-       
-
------ Tagged ld64-74.1
-
-2007-05-09     Nick Kledzik    <kledzik@apple.com>
-       
-       * src/Options.h: add emitWarnings()
-       * src/Options.cpp: wire up -w to emitWarnings()
-
-
-2007-05-09     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5137285> ld64 won't link wine (regression from Tiger)
-       * src/Architectures.hpp: add x86::kPointerDiff16 and x86::kPCRel16
-       * src/MachOReaderRelocatable.hpp: add support to parse new relocs
-       * src/MachOWriterExecutable.hpp: add support fo new relocs
-       
-
-2007-05-08     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5182537> need way for ld and dyld to see different exported symbols in a dylib
-       * src/MachOReaderDylib.hpp: update parse and use $ld$ symbols
-       * src/Options.h: move VersionMin to ReaderOptions
-       * src/ObjectFile.h: move VersionMin to ReaderOptions
-       * src/Options.cpp:  move VersionMin to ReaderOptions
-       * src/MachOWriterExecutable.hpp: move VersionMin to ReaderOptions
-       * unit-tests/test-cases/symbol-moving: added test case
-       
-
-2007-05-03     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5181105> typo in error message for linking -pie
-       * src/MachOWriterExecutable.hpp: fix typo in error messages
-       
-
------ Tagged ld64-74
-
-2007-05-03     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5171880> ld64 can't find @executable _path relative dylibs from our umbrella frameworks
-       <rdar://problem/4019497> ld64 should handle linking against dylibs that have @loader_path based dylib load commands
-       * src/ObjectFile.h: add from parameter to findDylib()
-       * src/MachOReaderDylib.hpp: supply from parameter to findDylib()
-       * src/ld.cpp: use from parameter for @loader_path substitution in findDylib()
-       * unit-tests/test-cases/re-export-relative-paths: added test case
-       
-
-2007-05-02     Nick Kledzik    <kledzik@apple.com>
-
-       * src/ObjectFile.h: add fLogObjectFiles and fLogAllFiles
-       * src/Options.cpp: hook up -t to fLogAllFiles and -whatsloaded to fLogObjectFiles 
-       * src/MachOReaderDylib.hpp: log if fLogAllFiles
-       * src/MachOReaderRelocatable.hpp: log if fLogObjectFiles or fLogAllFiles 
-       * src/MachOReaderArchive.hpp: log if fLogAllFiles
-       * doc/man/man1/ld.1: update man page
-
-
-2007-05-02     Nick Kledzik    <kledzik@apple.com>
-       
-       <rdar://problem/5177848> typo in message, frameowrk
-       * src/Options.cpp: fix typo
-
-
-2007-05-01     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4977301> "ld" man page is missing the description for many options 
-       * doc/man/man1/ld.1: add documentation on all obsolete options
-       
-       
-2007-05-01     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5113424> ld doesn't handle -mlong-branch .o files that have had local symbols stripped
-       <rdar://problem/4965359> warning about dwarf line info with -mlong-branch
-       * src/MachOReaderRelocatable.hpp: don't lop -mlong-branch stubs off end of functions
-       * src/MachOWriterExecutable.hpp: allow code references besides BR24 to be stubable
-       
-
-2007-04-30     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5065659> unable to link VTK because __textcoal_nt too large
-       * src/MachOReaderRelocatable.hpp: when doing a final link map __textcoal_nt to __text
-
-
-2007-04-30     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5062685> ld does not report error when -r is used and exported symbols are not defined.
-       <rdar://problem/4637139> ld leaves global common symbols not in exported symbols list.
-       * src/ld.cpp: stop special casing -r mode in checkUndefines() 
-       * src/MachOWriterExecutable.hpp: don't create proxy atom in -r mode if it is supposed to be exported.
-               mark tentative definitions are private extern in -r mode even without -keep_private_externs
-       * unit-tests/test-cases/exported_symbols_list-r: added test case
-
-
-2007-04-27     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5137732> ld should keep looking when it finds a weak definition in a dylib
-       * src/ld.cpp: modified addJustInTimeAtoms() to keep looking when a weak defintion is found
-       * unit-tests/test-cases/weak-def-ordinal: added test case
-       
-
-2007-04-27     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5166572> better error message for indirect dylibs missing required architecture
-       * src/ld.cpp: when loading indirect dylib add path to error messages
-
-
-2007-04-25     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5109373> the i386 slice of dyld does not need __IMPORT segment
-       * src/ObjectFile.h: add fForDyld
-       * src/Options.cpp: set up fForDyld
-       * src/MachOReaderRelocatable.hpp: if fForDyld, change __IMPORT segment to __DATA
-       * src/MachOWriterExecutable.hpp: recognize __DATA/__pointers in dyld as a non-lazy section
-
-
-2007-04-24     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5008421> ppc64: need to make LOCAL indirect symbol table entry for now local symbol
-       * src/MachOWriterExecutable.hpp: use INDIRECT_SYMBOL_LOCAL for any non-global symbol
-       * unit-tests/test-cases/strip_local: update test case
-       
-       
-2007-04-24     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5150407> ld64 -sectorder and -order_file files don't accept white space following the :
-       * src/Options.cpp: prune white space after colon and before symbol name
-       * unit-tests/test-cases/order_file: update test case to have a space after the colon
-       
-
-2007-04-24     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5055233> ld64 corrupts debug symbol table entries, nm doesn't print them
-       * src/MachOWriterExecutable.hpp: properly set ilocalsym in module table
-
-
-2007-04-24     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5066152> support __image_info in __DATA segment for 64-bits
-       * src/MachOReaderRelocatable.hpp: look for new objc info section name too
-
-
-2007-04-24     Nick Kledzik    <kledzik@apple.com>
-       
-       * src/MachOWriterExecutable.hpp: fix -non_global_symbols_strip_list to work with -r
-       * unit-tests/test-cases/local-symbol-partial-stripping: update test case
-
-
-
------ Tagged ld64-73.7
-
-2007-05-10     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5194804> can't use dtrace static probes in x86_64 dylib
-       * src/MachOWriterExecutable.hpp: x86_64:kPointerDiff32 is ok in shared region
-       * unit-tests/test-cases/dtrace-static-probes: update to build dylib too
-
-
-2007-05-09     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5191610> 9A430: using -dead_strip with static dtrace probes causes ld to crash
-       * src/ld.cpp: fix markLive() to look at right name in dtrace probe refernce
-       * unit-tests/test-cases/dtrace-static-probes: added -dead_strip case
-
-
------ Tagged ld64-73.6
-
-2007-04-17     Nick Kledzik    <kledzik@apple.com>
-       
-       <rdar://problem/5140897> Add options to do partial stripping of local symbols
-       * src/MachOWriterExecutable.hpp: use fOptions.keepLocalSymbol()
-       * src/Options.cpp: implement -non_global_symbols_no_strip_list and -non_global_symbols_strip_list
-       * src/Options.h: replace stripLocalSymbols() with localSymbolHandling() and keepLocalSymbol()
-       * doc/man/man1/ld.1: document -non_global_symbols_no_strip_list and -non_global_symbols_strip_list
-       * unit-tests/test-cases/local-symbol-partial-stripping: added test case
-       
-
------ Tagged ld64-73.5
-
-2007-04-17     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5129379> ld64-73.3 XBS logging incorrectly reporting "direct" dynamic libraries
-       * src/ld.cpp: restore direct vs indirect library for LD_TRACE_DYLIBS logging
-       
-
-2007-04-16     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5067034> data initialized to a weak imported symbol is missing relocation
-       * src/MachOWriterExecutable.hpp: check for A::kPointerWeakImport in buildExecutableFixups()
-       * unit-tests/test-cases/weak_import: updated test case to catch this problem
-
-
-2007-04-13     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5071047> Support -U 
-       * src/MachOWriterExecutable.hpp: create proxies for -U symbols
-       * src/Options.cpp: process -U 
-       * src/Options.h: add allowedUndefined() and someAllowedUndefines()
-       * src/ld.cpp: create proxies for -U symbols
-       * doc/man/man1/ld.1:  document -U and -undefined options
-       * unit-tests/test-cases/undefined-dynamic-lookup: added test case
-
-
------ Tagged ld64-73.4
-
-2007-04-12     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5125280> ld changes needed to support read-only DOF
-       * src/Options.cpp: remove -read_only_dof
-       * src/Options.h: remove fReadOnlyDOFs
-       * src/ld.cpp: only generate read-only DOF sections
-       
-
------ Tagged ld64-73.3.1
-
-2007-04-13     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5130496> -framework vecLib -framework Accelerate causes bad ordinals 
-       * src/MachOWriterExecutable.hpp: fix bug optimizeDylibReferences() when there are two readers with same install name
-
-
------ Tagged ld64-73.3
-
-2007-04-03     Nick Kledzik    <kledzik@apple.com>
-
-       * src/ld.cpp: read-only-dofs should use 32-bit offsets for x86_64
-       * src/MachOReaderDylib.hpp: if "public" re-export is not marked implict, still mark it as re-exported
-       
-
-2007-04-02     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5105971> if replacement file for -dylib_file is missing, warn instead of error
-       * src/ld.cpp: a try/catch to turn -dylib_file error into a warning.
-       * unit-tests/test-cases/dylib_file-missing: add test case
-       * doc/man/man1/ld.1: update man page about -dead_strip_dylibs
-       
-
------ Tagged ld64-73.2
-
-2007-03-31     Nick Kledzik    <kledzik@apple.com>
-       
-       <rdar://problem/5102873> ld64-73: atom sorting error with duplicate zero sized bss symbols
-       * src/MachOReaderRelocatable.hpp: suppress warning on sorting zero size zero fill atoms
-       
-2007-03-31     Nick Kledzik    <kledzik@apple.com>
-       
-       <rdar://problem/5102845> ld64-73 fails anything linking with -lm
-       * src/ld.cpp: when processing dylbs that are sylinks ensure that fDylibMap contains all paths  
-       * src/MachOWriterExecutable.hpp: when dead stripping dylibs and renumbering ordinals make sure
-               aliases dylib get renumbered too
-       * unit-tests/test-cases/dylib-aliases: added
-       
-       
------ Tagged ld64-73.1
-       
-2007-03-30     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOWriterExecutable.hpp: back out use of LC_REEXPORT_DYLIB until rdar://problem/5009909 is in build fleet
-       
-       
------ Tagged ld64-73
-       
-2007-03-30     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4175790> ER: -dead_strip_dylibs
-       <rdar://problem/3904828> linker should add implicit load commands for indirectly used public dylibs
-       * src/ObjectFile.h: change dylib reader interface to implictly/explicitlyLinked
-       * src/ld.cpp: use new dylib reader interface
-       * src/Options.h: add deadStripDylibs()
-       * src/Options.cpp: support -dead_strip_dylibs
-       * src/MachOReaderDylib.hpp: use new dylib reader interface
-       * src/MachOWriterExecutable.hpp: remove dylib load commands for unused dylibs and alter ordinals 
-       * unit-tests/test-cases/re-export-optimizations: added
-       * unit-tests/test-cases/dead_strip_dylibs: added
-       
-
-2007-03-30     Nick Kledzik    <kledzik@apple.com>
-
-       * src/Options.cpp: enable -lfoo to search for libfoo.so as well as libfoo.dylib, 
-               remove seg addr table hack for transitioning to new linker
-
-2007-03-30     Nick Kledzik    <kledzik@apple.com>
-       
-       <rdar://problem/5073800> ADOBE XCODE3: Linker is slow with large C++ .o files
-       * src/MachOReaderRelocatable.hpp: the compiler generates stubs to weak functions in the
-               same translation unit.  Don't treat those like the spurios stubs to static functions.
-
-
-2007-03-29     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4739044> ld64 should link mach_kernel during xnu builds to support dtrace
-       * src/MachOReaderRelocatable.hpp: To handle duplicate labels properly, rework how atoms sizes are set 
-               by iterating through sorted fAtoms rather than fAddrToAtom, . Change default alignment of commons
-               to be the natural alignment of the size rounded up to the closest power of two and max it at 12.
-               Build atoms in reverse symbol table order so that global atoms are constructed before locals.
-               This assures that if there is a global and local label at the same location, the global label
-               will become the atom's name and the local will be an alias.  Properly handle a label
-               at the end of a section.  Handle R_ABS in relocations.  Handle sect-diff relocs with addends.
-               Don't auto-strip 'l' symbols in static executables (mach_kernel).
-       * src/OpaqueSection.hpp:  opaque_section now has an ordinal
-       * src/ld.cpp: opaque_section now requires an ordinal
-       * src/ObjectFile.h: add ReaderOptions.fForStatic
-       * src/Options.cpp: set fForStatic when building a static executable
-       * src/MachOWriterExecutable.hpp: add from atom to StubAtom<ppc>.  Properly write out i386
-               sect-diff relocs with addends.  properly write out ppc PICbase relocs where pic base
-               is not in the atom.
-
-
-2007-03-27     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5085863> Typo in ld man page (-exported_symbols_list)
-       * doc/man/man1/ld.1: fix typo
-       
-
-2007-03-26     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4727750> consider generating LC_UUID from a checksum of the file
-       * src/Options.h: change emitUUID() to getUUIDMode()
-       * src/Options.cpp: support -random_uuid
-       * src/MachOWriterExecutable.hpp: set uuid to be md5 hash of entire output file
-       
-
-2007-03-24     Nick Kledzik    <kledzik@apple.com>
-       
-       * src/MachOWriterExecutable.hpp: restructure writeAtoms() to copy all atoms in memory if possible
-
-
-2007-03-24     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5082603> ld -r of stripped .o file can incorrectly merge non-lazy pointers
-       * src/MachOWriterExecutable.hpp: when generating a .o file, non-lazy pointer with target offsets should be
-               encoded as LOCAL in the indirect symbol table
-       * unit-tests/test-cases/stripped-indirect-symbol-table: added test case
-
-
-2007-03-23     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5084564> SWB: ld64-72 errors building with gcc-4.2      
-       * src/MachOReaderDylib.hpp: add curly brackets in switch cases
-       * src/MachOWriterExecutable.hpp: rearrange classes so there are no template specialization forward references
-
-
-2007-03-23     Nick Kledzik    <kledzik@apple.com>
-
-       * src/ld.cpp: fix -print_statistics when using -dead_strip
-
-
-2007-03-23     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.hpp: generate better names for non-lazy pointers to the interior of atoms
-
-
-2007-03-16     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOWriterExecutable.hpp: speed up ld -r a little by reversing relocs en mas
-
-
-2007-03-16     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4975277> ld Bus Error on missing command line arguments
-       * src/Options.cpp: check next argv[] is not NULL
-
-
-2007-03-16     Nick Kledzik    <kledzik@apple.com>
-       
-       <rdar://problem/4832049> need to be able to order symbols in anonymous namespaces
-       * src/ld.cpp: add logic to do fuzzy matching of symbols with anonymous namespace usage
-       * unit-tests/test-cases/order_file-ans: added test case
-
-
-2007-03-16     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5042552> headerpad_max_install_names deprecated for 64-bit
-       * src/ld.cpp: make sure dylib load command order matches command line order
-       * src/Options.h: add maxMminimumHeaderPad()
-       * src/Options.cpp: add maxMminimumHeaderPad() set by -headerpad_max_install_names
-       * src/src/MachOWriterExecutable.hpp: check maxMminimumHeaderPad()
-       * doc/man/man1/ld.1: update man page about -headerpad_max_install_names
-
-
-2007-03-16     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4592484> Linker returns success although exported symbols are undefined.
-       * src/ld.cpp: turn missing symbols back into an error
-
-
-2007-03-16     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4019497> ld64 should handle linking against dylibs that have @loader_path based dylib load commands
-       * unit-tests/test-cases/loader_path: added test case
-       
-
-2007-03-16     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/3904828> linker should add implicit load commands for indirectly used public dylibs
-       <rdar://problem/4142277> Indirect libraries should be found using -F and -L options
-       <rdar://problem/4607755> Simplier, generalized way to re-export dylibs: LC_REEXPORT_DYLIB
-       * src/ld.cpp: reworked all dylib processing.  Readers can now add the dylib list.
-       * src/Options.h: add findFileUsingPaths()
-       * src/MachOReaderDylib.hpp: look in re-exported children instead of requring linker to do that
-       * src/ObjectFile.h: add processIndirectLibraries(), remove getDependentLibraryPaths()  
-       * src/machochecker.cpp: support LC_REEXPORT_DYLIB
-    * src/ExecutableFile.h: simplify DyLibUsed
-       * src/Options.cpp: add findFileUsingPaths().  add new re-export options
-       * src/MachOWriterExecutable.hpp: Use LC_REEXPORT_DYLIB when targetting 10.5
-       * doc/man/man1/ld.1: updated with new re-export options
-       * unit-tests/test-cases/indirect-path-search: added tests that -F and -L work with indirect dylibs
-       * unit-tests/test-cases/re-export-cases: added tests for all combinations of re-exporting
-       
-
-2007-03-14     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4982400> sort external relocations to optimize dyld performance 
-       * src/MachOWriterExecutable.hpp: added ExternalRelocSorter
-       * src/machochecker.cpp: verify external relocations are grouped by symbol number
-       * unit-tests/test-cases/external-reloc-sorting: added test case
-       
-       
------ Tagged ld64-72
-
-2007-03-06     Nick Kledzik    <kledzik@apple.com>
-
-       * src/Options.cpp: ignore .objc_category_name_* symbols in .exp files
-       
-
-2007-03-06     Nick Kledzik    <kledzik@apple.com>
-
-       * src/Options.cpp: stop special casing mach_kernel and instead requre kernel to be built with -new_linker 
-       
-
-2007-03-06     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5044253> ld64-72 (experimental) is causing DejaGnu test failures
-       * src/MachOWriterExecutable.hpp: add optimizableGOTReferenceKind() to track GOT uses that cannot be optimized
-
-
-2007-03-06     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5026135> minimum header padding should be 32 to allow code signing
-       * src/Options.cpp: initialize fMinimumHeaderPad to 32
-       * src/MachOWriterExecutable.hpp: better calculation of header padding 
-       
-
-2007-03-06     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5033206> Linker crashes with -flat_namespace against two-level dylibs that might have re-exports
-       * src/ld.cpp: flat namespace should not allow NULL indirect readers
-
-
-2007-03-06     Nick Kledzik    <kledzik@apple.com>
-               
-       * src/MachOReaderRelocatable.hpp: don't error on S_COALESCED sections with anonymous atoms
-       * src/MachOWriterExecutable.hpp: set MH_PIE bit when linking -pie
-       * ld64.xcodeproj/project.pbxproj: don't echo environment when running unit test
-
-
-2007-03-01     Nick Kledzik    <kledzik@apple.com>
-
-       * doc/man/man1/ld.1: Add descriptions to all "rarely used options"
-
-
-2007-03-01     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4971033> Remove support for Essential Symbols: Warn about use of -Sp option; remove man page entry
-       * src/Options.cpp: make -Sp obsolete
-       * doc/man/man1/ld.1: make -Sp obsolete
-       
-
-2007-03-01     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/5040314> Support -pie   
-       * src/Options.h: Add positionIndependentExecutable()
-       * src/Options.cpp: Support -pie option to set positionIndependentExecutable()
-       * src/MachOWriterExecutable: if -pie is used, add extra local relocations and error if any
-               absolute addressing is used
-               
-
-2007-03-01     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4739044> ld64 should link mach_kernel during xnu builds to support dtrace
-       * src/ld.cpp: Ensure segments are laid out in discovery order.  Add support for kAbsoluteSymbol.
-                       Warn when merging symbols of different visiblity.  Warn when a tentative definition 
-                       is replaced by one a real definition with a smaller size.  Lay out __common section
-                       so that ones built with -fno-commons come before regular commons.
-       * src/ObjectFile.h: remove SegmentOffset ivar and getter/setters
-       * src/machochecker.cpp: allow images with no r/w segments
-       * src/MachOReaderRelocatable: Add AbsoluteAtom.  Sort tentative definitions by name instead of by size
-                       Add support for custom commons alignment.  
-       * src/Options.cpp: Fix spurious -sectalign warnings.  Don't use ld_classic when linking mach_kernel
-       * src/MachOWriterExecutable.hpp: Support kAbsoluteSymbol atoms. In -r mode, set custom alignment 
-                       for commons if alignment is not its size.  Support global __dtrace_probe labels.
-       * src/ObjectDump.cpp: add support for kAbsoluteSymbol atoms.
-       * unit-tests/test-cases/commons-alignment: Added test case for custom commons alignment
-       * unit-tests/test-cases/absolute-symbol: Added test case for basic absolute symbols
-       * unit-tests/test-cases/segment-order: Added test case that segments lay out in discovery order
-       * unit-tests/test-cases/commons-order: Added test case that commons lay out correctly
-       * unit-tests/test-cases/end-label: Added test case that a label used to mark the end of a section does not
-                       get associcated with the next section.
-       
-
-2007-02-23     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/3965017> gcc-5005: DejaGnu failures due to -frepo
-       * src/ld.cpp: Add quotes to referenced from name to make collect2 and -frepo happy
-       
-
-2007-02-22     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOWriterExecutable.hpp: rework how padding after load commands is calculated
-
-
-2007-02-21     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOWriterExecutable.hpp: extend special case of __mh_execute_header to static executables too
-
-
-2007-02-21     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/3882294> gcc link map option ( "-M" ) should be redirectable to file
-       * doc/man/man1/ld.1: added -map option description
-       * src/Options.h: added generatedMapPath()
-       * src/Options.cpp: set up generatedMapPath() if -map option is used
-       * src/MachOWriterExecutable.hpp: add writeMap() method to generate map file
-
-
-2007-02-19     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4557734> Implement GOT Load elimination optimization
-       * src/ld.cpp: track size of all atoms and if > 2GB sort large zero-fill atoms to end
-       * src/MachOWriterExecutable.hpp: If image size < 2GB, only generate GOT entries if value must be
-       updatable by dyld.  If > 2GB, only eliminate GOT entries to non-zero-fill atoms.  Any use
-       of an eliminated GOT entry has its code changed from MOVQ _foo@GOT(%rip) to LEAQ _foo(%rip).
-       * unit-tests/test-cases/large-data: added
-       * unit-tests/test-cases/got-elimination: added
-
-
------ Tagged ld64-71.2
-
-2007-02-13     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4995303> new ld ignores -segprot option
-       * src/Options.h: expose customSegmentProtections()
-       * src/Options.cpp: parse -segprot option and populate customSegmentProtections()
-       * src/MachOWriterExecutable.hpp: use customSegmentProtections()
-
-
-2007-02-13     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4988068> i386 -stack_addr doesn't work
-       * src/MachOWriterExecutable.hpp: use correct offset into thread state record
-
-
------ Tagged ld64-71.1
-
-2007-02-07     Nick Kledzik    <kledzik@apple.com>
-
-       * src/ld.cpp: sort __OBJC2 segment to be next to __OBJC segment
-
-
-2007-02-07     Nick Kledzik    <kledzik@apple.com>
-
-       * src/Options.cpp: change missing -seg_addr_table from an error to a warning
-
-
-2007-02-06     Nick Kledzik    <kledzik@apple.com>
-       
-       <rdar://problem/4977311> Leopard 9A357: -dylib_file broken?
-       * src/MachOWriterExecutable.hpp: remove use of fInstallPathOverride
-       * src/Options.cpp: wire up -dylib_file option 
-       * src/Options.h: remove fInstallPathOverride.  add fDylibOverrides
-       * src/ld.cpp: check dylibOverrides() for indirect libraries
-       * unit-tests/test-cases/dylib_file: add test case
-       
-
-2007-02-05     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderDylib.hpp: don't warn about zero size __image_info sections
-
-
-2007-02-04      Rick Balocca    <rbalocca@apple.com>
-       Enable the failing cases for missing command line arguments
-
-2007-02-04      Rick Balocca    <rbalocca@apple.com>
-       Make sure that all .o's are checked by ObjectDump
-       and all macho are checked by machochecker
-
-2007-02-04      Rick Balocca    <rbalocca@apple.com>
-       Fix an endian problem with machochecker
-       Fix blank-stubs Makefile
-
------ Tagged ld64-71
-
-2007-02-02      Rick Balocca    <rbalocca@apple.com>
-       blank-stubs test case: handle the case of a native ppc compile--this
-       sets the subtype, which must be passed to lipo
-
-2007-02-01      Rick Balocca    <rbalocca@apple.com>
-       make cpu-sub-types test more robust
-
-2007-02-01      Rick Balocca    <rbalocca@apple.com>
-       auto-arch tests were resulting in a false FAILs
-
-2007-02-01      Rick Balocca    <rbalocca@apple.com>
-       test cpu-sub-types was resulting in a false FAIL
-
-2007-02-01      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4969335> STD:VSC: c99 -o writes to file that does not have write permission
-       * src/MachOWriterExecutable.hpp: check file is writable before using it
-
-2007-02-01      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4965743> debug map (N_OSO) timestamps for object files in ranlib archive are incorrect
-       * src/MachOReaderArchive.hpp: parse modTime for .o files out of archive header
-
-2007-01-31      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4967535> 9A354: ld -all_load does *NOT* produce the same dSYM as *.o or -u
-       * src/ld.cpp: when using -all_load don't assume that all atoms have same reader
-       * unit-tests/test-cases/dwarf-archive-all_load: added
-
------ Tagged ld64-70.1
-
-2007-01-31      Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOWriterExecutable.hpp: in addObjectRelocs_powerpc() mask scattered r_address to 16-bits
-
------ Tagged ld64-70
-
-
-2007-01-30      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4810668> linker should verify GC consistency of modules being linked into library
-       <rdar://problem/4474195> Support cpu-sub-types for ppc
-       * src/ObjectFile.h: Add getObjCConstraint() and getCpuConstraint()
-       * src/MachOReaderRelocatable.hpp:  don't make atom for __image_info section, instead parse constaints
-       * src/MachOReaderDylib.hpp: look at __image_info content to get constaints
-       * src/ld.cpp: add updateContraints() and checkObjc()
-       * src/MachOWriterExecutable.hpp: add ObjCInfoAtom to sythesize __image_info content
-       
-       
-2007-01-28      Nick Kledzik    <kledzik@apple.com>
-
-       src/*: remove ObjectFile::requiresFollowOnAtom() method
-       
-
-2007-01-28      Nick Kledzik    <kledzik@apple.com>
-
-       src/ld.cpp: enable LLVM_SUPPORT by default
-       src/LLVMReader.hpp: don't use absolute paths for llvm headers and libraries
-       
-
-2007-01-26      Rick Balocca    <rbalocca@apple.com>
-       * src/ObjectDump.cpp: The usage() message was incorrect.
-
-
-2007-01-25      Rick Balocca    <rbalocca@apple.com>
-       * unit-tests/test-cases/zero-fill3:  It was reporting FAIL on ld64 error return.
-               It should have been checking for non-error return.
-
-
-2007-01-24      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4952297> x86 fast stubs should not cross 64-byte boundries
-       * src/MachOWriterExecutable.hpp: for x86, 64-byte align __jump_table section 
-       and make 64-btye crossing stubs be empty entries with indirect symbol table 
-       entry of INDIRECT_SYMBOL_ABS
-
-
-2007-01-19      Nick Kledzik    <kledzik@apple.com>
-
-       * src/Options.h: add readOnlyx86Stubs()
-       * src/Options.cpp: support -read_only_stubs
-       * src/MachOWriterExecutable.hpp: make __IMPORT segment not writable if -read_only_stubs is used
-       
-
-2007-01-16  Eric Christopher  <echristo@apple.com>
-
-       <rdar://problem/4856341> ld64 --help isn't recognized
-       * src/Options.cpp (Options::parse): Support --help and -help.
-
-
-2007-01-15      Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOFileAbstraction.hpp: add range checking on macho_scattered_relocation_info::set_r_address()
-
-
-2007-01-14      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4514409> Support wildcards in contents of -exported_symbols_list
-       * src/Options.h: add SetWithWildcards class
-       * src/Options.cpp: add -exported_symbol and -unexported_symbol and use SetWithWildcards
-       * doc/man/man1/ld.1: add -exported_symbol and wildcard explanation
-       * unit-tests/test-cases/exported-symbols-wildcards: added test case
-
-
-2007-01-10      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4868270> [U]SDT probes should use C calling convention
-       * src/Options.cpp: Add -read_only_dof
-       * src/ld.cpp: create __dof section(s) based on probe and isenabled sites
-       * src/MachOReaderRelocatable.hpp: parse new sdt 2.0 probes encoded in .o files
-       * src/MachOWriterExecutable.hpp: handle regenerating dtrace probes into .o files
-       * unit-tests/test-cases/dtrace-static-probes: added test case
-
-
------ Tagged ld64-69.8
-
-2007-01-30      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4964508> Support LD_FORCE_NO_SEG_ADDR_TABLE
-       * src/Options.cpp: Support LD_FORCE_NO_SEG_ADDR_TABLE
-       
-
------ Tagged ld64-69.7
-
-2007-01-25      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4949507> Leopard9A351: CFM Apps Are Broken because CFM glue is missing
-       * src/MachOReaderRelocatable.hpp: check S_ATTR_NO_DEAD_STRIP in dontDeadStrip()
-
-
------ Tagged ld64-69.6
-
-2007-01-24      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4947347> LD_TRACE_ARCHIVES should only print out when a .o is actually used from an archive
-       * src/ld.cpp: create and use logArchive() 
-
-       
------ Tagged ld64-69.5
-
-2007-01-22      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4946075> 9A350: can't link ppc programs with ld_classic
-       * src/Options.cpp: Remove support for LD_NO_CLASSIC_LINKER. Add support for -classic_linker
-
-       
------ Tagged ld64-69.4
-       
-2007-01-17      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4925645> QTComponents does not link with ld64
-       * src/MachOReaderRelocatable.hpp: handle N_RSYM and N_PSYM stabs
-
-       
------ Tagged ld64-69.3
-
-2007-01-03      Nick Kledzik    <kledzik@apple.com>
-
-       * src/Options.cpp: If the same dylib is specified twice and the second is specified weak, make it weak
-
-
------ Tagged ld64-69.2
-
-2006-12-18      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4889729> -dead_strip without -exported_symbols_list should not strip global functions from archives
-       * src/ld.cpp: when adding a .o file from an archive, add all its global symbols to live roots
-       * unit-tests/test-cases/dead_strip-archive: added
-
-
-2006-12-18      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4889409> flat_namespace main executables do not need to indirect interior references
-       * src/MachOWriterExecutable.hpp: don't indirect references to global symbols in main executables
-       * unit-tests/test-cases/flat-main: updated to test for indirection
-       * unit-tests/test-cases/flat-dylib: added
-
-
------ Tagged ld64-69.1
-
-2006-12-15      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4886721> -flat_namespace does not work with -mdynamic-no-pic
-       * src/MachOWriterExecutable.hpp: rework checking for use of ppc absolute addressing to allow them as long as
-         the target is within the same linkage unit.
-
-
-2006-12-15      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4886652> -ObjC should only load .o with .objc_ symbols
-       * src/Options.cpp: remove warning from -ObjC and have it instead set fLoadAllObjcObjectsFromArchives
-       * src/MachOReaderArchive.hpp: when -ObjC is used, preload all .o files from archives that contain .objc_ symbols
-
-
------ Tagged ld64-69
-
-2006-12-13      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4879913> prebound interior pointers must be non-zero
-       * src/MachOWriterExecutable.hpp: in fixUpReference_powerpc() set lazy pointers bound to with the dylib to
-        their target value. Properly set REFERENCE_FLAG_UNDEFINED_* flags in reference table and n_desc
-
-
-2006-12-09      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4868738> ld64 fails to detect error that ld_classic does
-       * src/MachOWriterExecutable.hpp: check for absolute reloc to an external symbol
-       * src/MachOReaderRelocatable.hpp: ignore -mlong-branch stubs in .o files
-
-
-2006-12-09      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4874209> symbols with REFERENCED_DYNAMICALLY should never be stripped
-       * src/MachOWriterExecutable.hpp: update Writer<A>::shouldExport() to check for kSymbolTableInAndNeverStrip
-       * unit-tests/test-cases/main-stripped: add test that dynamically referenced symbol cannot be stripped
-
-
-2006-12-08      Nick Kledzik    <kledzik@apple.com>
-
-       * unit-tests/test-cases/allowable-client: add variant test cases (e.g. CoreServices_profile)
-       * src/ld.cpp: allow frameworks with variant install names (e.g. CoreServices_profile) to be private clients
-
-
-2006-12-08      Nick Kledzik    <kledzik@apple.com>
-
-       * doc/man/man1/ld.1: rewrite man page
-       * src/Options.h: add warnObsolete()
-       * src/Options.cpp: use warnObsolete() on many options.  Make nonWeak the weak-mis-match default.
-               Make -ObjC mean -all_load.
-
------ Tagged ld64-68.3
-
-2006-12-05      Nick Kledzik    <kledzik@apple.com>
-
-       * src/ld.cpp: allow umbrella frameworks to have variant install names (e.g. CoreServices_profile) and still link
-
-
------ Tagged ld64-68.2
-
-2006-12-05      Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOWriterExecutable.cpp: Use N_PBUD in the symbol table for undefined symbols in prebound dylibs
-
-
------ Tagged ld64-68.1
-
-2006-12-01      Nick Kledzik    <kledzik@apple.com>
-
-       * src/Options.cpp: always generate module tables for 32-bit architectures so that ld_classic
-               can link against them
-
-
------ Tagged ld64-68
-
-2006-12-01      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4858299> seg_addr_table needs matching fuzziness
-       * src/Options.cpp: special case a how a dozen dylib are looked up in the seg_addr_table
-
-
-2006-12-01      Nick Kledzik    <kledzik@apple.com>
-
-       * src/Options.cpp: have all -static links for 32-bit archs roll over to ld_classic unless
-               LD_NO_CLASSIC_LINKER_STATIC is set.
-       * unit-tests/bin/make-recursive.pl: set LD_NO_CLASSIC_LINKER_STATIC for unit tests
-
-
-2006-11-29      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4855542> ld64-67: QTComponents fails to build
-       * src/MachOReaderRelocatable.hpp: don't error out when a local non-lazy pointer does not point to a symbol
-       * unit-tests/test-cases/strip_local: added test case
-
-
-2006-11-28      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4433496> Need a way to mark libraries usable by dynamic linker but unusable by static linker
-       * src/Options.cpp: allow -client_name to be used with main executables
-       * src/ld.cpp: generalize -allowable_client.  Any dylib can now restrict who can link against it.  As a convention
-               linking with -allowable_client '!' will mean no one can statically link with the dylib.  It can still be loaded
-               dynamically, or by any existing clients, but no new clients can link with it.
-       * unit-tests/test-cases/allowable-client/Makefile: enable previously commented out test cases.  Add test cases
-               of a dylib that allows no clients and just one client
-
-2006-11-27      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4795615> -final_output should be used if -install_name not used
-       * src/Options.cpp: fall back to using -final_output for install name
-
-
------ Tagged ld64-67
-
-2006-11-17      Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOWriterExecutable.hpp: support __IMPORT segment being slide independently of __DATA segment in shared cache
-
-
-2006-11-16      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4838262> 9a303: ld -filelist Bus Error
-       * src/Options.cpp: add check that -filelist is followed by an argument
-
-
-2006-11-16      Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOWriterExecutable.hpp: when building split-seg dylibs, LINKEDIT goes in read-only side
-
-
-2006-11-15      Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOWriterExecutable.hpp: set proper attributes for __eh_frame in ld -r mode
-       * unit-tests/test-cases/eh_frame: added test case
-
-
-2006-11-10      Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.hpp: redirect references to static weak stubs to the real target
-
-
-2006-11-09      Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOWriterExecutable.hpp: r_address is offset from first LC_SEGMENT vmaddr - not from segment with lowest address
-
-
------ Tagged ld64-66.1
-
-2006-11-09      Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOWriterExecutable.hpp: initialize fModuleInfoAtom to zero
-
-
-2006-11-08      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4821985> FSF GCC's libjava doesn't link with Ochre ld64
-       * src/MachOReaderRelocatable.hpp: ignore debug_line section if debug_info section is missing or empty
-
------ Tagged ld64-66
-
-2006-11-07      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4824368> SWB: d64-65 does not built usage split-seg dylibs
-       * src/MachOWriterExecutable.hpp: when prebinding split-seg correctly set r_address fields and on
-       disk values for external relocations
-       * unit-tests/test-cases/prebound-split-seg: added test case
-
-
-2006-11-03      Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderDylib.hpp: don't report dependent libraries if MH_NO_REEXPORTED_DYLIBS bit is set
-       * src/MachOWriterExecutable.hpp: set MH_NO_REEXPORTED_DYLIBS bit if dylib does not logically re-export any other dylibs
-       * unit-tests/test-cases/re-export-flag: added test case
-       * src/machochecker.cpp: validate use of MH_NO_REEXPORTED_DYLIBS
-
-
-2006-11-02      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4814565> Mysterious messages from ld64 with MACOSX_DEPLOYMENT_TARGET = 10.5
-       * src/MachOWriterExecutable.hpp: kPointerWeakImport is a valid reference type to cross segments
-
-
-2006-11-02      Nick Kledzik    <kledzik@apple.com>
-
-       * src/Options.cpp,h: Add support for -rpath
-       * src/MachOFileAbstraction.hpp: add macho_rpath_command
-       * src/MachOWriterExecutable.hpp: add RPathLoadCommandsAtom to create LC_RPATH for each -rpath
-
-
------ Tagged ld64-65
-
-2006-10-30      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4729162> x86_64 default stack_addr is wrong
-       * src/Options.cpp: change default 64-bit stack location when using -stack_size
-
-
-2006-10-30      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4474316> dylibs need modules for 10.3 and for ld_classic in Salt
-       * src/MachOWriterExecutable.hpp: add ModuleInfoLinkEditAtom to create module table stuff
-       * src/Options.cpp,h: Add needsModuleTable()
-       * src/MachOFileAbstraction.hpp: Add macho_dylib_module, macho_dylib_reference, and macho_dylib_table_of_contents
-
-
-2006-10-27      Nick Kledzik    <kledzik@apple.com>
-
-       * unit-tests/test-cases/no-uuid/Makefile: add -gstabs+ to be compatible with latest compiler
-       * unit-tests/test-cases/stabs-coalesce/Makefile: add -gstabs+ to be compatible with latest compiler
-
-
-2006-10-26      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4585230> i386 -mdynamic-no-pic switch statement jump table is out of line
-       * src/MachOWriterExecutable.hpp: for i386 don't check for direct references to weak symbols
-
-
-2006-10-26  Devang Patel  <dpatel@apple.com>
-
-       * src/LLVMReader.hpp: Supply final output file path to optimizer.
-
-2006-10-26  Devang Patel  <dpatel@apple.com>
-
-       * src/ObjectFile.h: Make setSection* methods virtual.
-       * src/LLVMReader.hpp: Override setSection* methods.
-
-2006-10-26  Devang Patel  <dpatel@apple.com>
-
-       * unit-tests/test-case/llvm-integration/a13.h: New.
-       * unit-tests/test-case/llvm-integration/a13.cc: New.
-       * unit-tests/test-case/llvm-integration/main13.cc: New.
-
-2006-10-26  Devang Patel  <dpatel@apple.com>
-
-       * src/options.h, src/options.cpp: Add -save-temps command line option.
-       * src/LLVMReader.hpp: Use saveTemps option.
-
-
-2006-10-26  Devang Patel  <dpatel@apple.com>
-
-       * src/LLVMReader.hpp: Remove invalid module from memory.
-
-2006-10-26  Devang Patel  <dpatel@apple.com>
-
-       * src/LLVMReader.hpp: Collect symbol alignment info from LLVM optimizer.
-
-2006-10-21  Eric Christopher  <echristo@apple.com>
-
-       * src/ld.cpp (Linker::Linker): Check for LD_NO_CLASSIC_LINKER before
-       invoking ld_classic.
-       * unit-tests/test-cases/relocs-literals/Makefile: Run for -mdynamic-no-pic
-       and pic.
-       * unit-tests/test-cases/static-executable/Makefile: Skip for 64-bit. Add
-       -dead_strip to command line.
-
------ Tagged ld64-64.2
-
-2006-10-19      Nick Kledzik    <kledzik@apple.com>
-
-       * ld64.xcodeproj/project.pbxproj: stop copying LLVMReader.hpp into man1 directory
-
------ Tagged ld64-64.1
-
-2006-10-19      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4791643> ld64-63.1 erroneously coalesces an empty string with a non-empty string
-       * src/MachOReaderRelocatable.hpp: rework cstring parsing to not assume all strings are start
-         at section alignment boundaries, and when coalescing empty strings always use one with greatest
-         alignment requirement
-       * src/MachOWriterExecutable.hpp: in -r mode, don't pad end of cstring section
-       * src/ObjectFile.h: correctly name leadingZeros() as trailingZeros()
-       * src/ld.cpp: leadingZeros() --> trailingZeros()
-
-
-2006-10-18  Eric Christopher  <echristo@apple.com>
-
-       * unit-tests/test-cases/read-only-relocs/Makefile: Skip for x86_64.
-       * unit-tests/test-cases/llvm-integration/Makefile: Skip if llvm isn't
-       present.
-
-2006-10-18      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4783853> ld64 change required to go with assembler cstring change
-       <rdar://problem/4732996> ld64 should error when a local relocation references an address outside its section
-       * src/MachOReaderRelocatable.hpp: for x86_64  in order to work with local or external relocations to cstrings
-       change parser to allow atoms with a pending name that is resolved after references are instantiated.
-       Make direct references to kRegularDefinition atoms.
-       * src/MachOWriterExecutable.hpp: in -r mode for x86_64 generate L* labels for cstrings and use external relocations
-       * unit-tests/test-cases/relocs-literals/test.c: add two cases of cstring literal plus addend
-
-
-2006-10-06      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4786250> check MACOSX_DEPLOYMENT_TARGET if -macosx_version_min is not used
-       * src/Options.cpp: if -macosx_version_min is not used, check MACOSX_DEPLOYMENT_TARGET, if
-       that is unused, default to 10.5
-
------ Tagged ld64-64
-
-2006-10-06      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4756806> crash in ppc64 program - bl to saveFP, but saveFP is too far away?
-       * src/MachOWriterExecutable.hpp: in addPPCBranchIslands(), properly account for growth of __text
-
-
-2006-10-06      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4769120> Linker-defined alias converts reference into definition and generates error.
-       * src/MachOReaderRelocatable.hpp: only alias symbols actually in the symbol table
-
-
-2006-10-06      Nick Kledzik    <kledzik@apple.com>
-
-       * unit-tests/test-cases/dwarf-debug-notes/Makefile: crt1.o no longer has stabs, so don't need to strip it
-       * unit-tests/test-cases/dwarf-debug-notes-r/Makefile: crt1.o no longer has stabs, so don't need to strip it
-
-
-2006-10-06      Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.hpp: rework dwarf line parsing to fix warnings that starting
-       showing up with gcc-5421
-
-
-2006-10-05  Eric Christopher  <echristo@apple.com>
-
-       <rdar://problem/4760935> ld64 needs to support libtool options
-       * src/Options.cpp (Options::parse): Add -noall_load, -install_name,
-       -current_version and -compatibility_version.
-
-2006-10-03  Eric Christopher  <echristo@apple.com>
-
-       * src/Options.cpp (Options::gotoClassicLinker): Use execvp
-       to call ld_classic.
-
-2006-10-03  Eric Christopher  <echristo@apple.com>
-
-       * unit-tests/test-cases/tentative-to-real/Makefile: Clean up after tests.
-
-2006-10-03  Eric Christopher  <echristo@apple.com>
-
-       * unit-tests/include/common.makefile (VALID_ARCHS): Add x86_64.
-       (OTOOL): Remove munging based on ARCH.
-
-2006-09-29      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4743925> problem merging .o files built with and without -fno-common
-       src/Options.*: make MakeTentativeDefinitionsReal a reader option
-       src/ObjectFile.h: make MakeTentativeDefinitionsReal a reader option
-       src/MachOWriterExecutable.hpp: make MakeTentativeDefinitionsReal a reader option
-       src/MachOReaderRelocatable.hpp: only assign a section name of __common to
-               tentative defintions when making a final linked image
-
-
-2006-09-28      Nick Kledzik    <kledzik@apple.com>
-
-       src/Options.h/.cpp: add support for -segaddr option
-       src/MachOWriterExecutable.hpp: In Writer::assignFileOffsets(), use -segaddr info
-
-
-2006-09-28      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4587349> Emit new CPU subtypes for ppc64 and x86-64 when targeting 10.5 or later
-       src/MachOWriterExecutable.hpp: set high bit of cpusubtype of 64-bit main executables when targeting 10.5 or later
-
-
-2006-09-28     Devang Patel    <dpatel@apple.com>
-
-       Add LLVM LTO support
-       src/LLVMReader.hpp: New file.
-       src/ld.cpp: Add optimization phase. Use LLVM LTO.
-       unit-tests/test-cases/llvm-integration: New tests.
-
-2006-09-27      Nick Kledzik    <kledzik@apple.com>
-
-       ld64.xcodeproj/project.pbxproj: remove accidental install of source file into man1
-
-
-2006-09-25      Nick Kledzik    <kledzik@apple.com>
-
-       src/Architectures.hpp: add kPointerDiff16 for ppc and ppc64
-       src/MachOReaderRelocatable.hpp: support kPointerDiff16
-       src/MachOWriterExecutable.hpp: support kPointerDiff16
-
------ Tagged ld64-63.1
-
-2006-09-22      Nick Kledzik    <kledzik@apple.com>
-
-       src/MachOWriterExecutable.hpp: include stubs in LC_SEGMENT_SPLIT_INFO
-
-
-2006-09-21      Nick Kledzik    <kledzik@apple.com>
-
-       src/Options.cpp: disable split-seg dylibs for 64-bit architectures
-
-
-2006-09-19      Nick Kledzik    <kledzik@apple.com>
-
-       src/MachOReaderRelocatable.hpp: rework __cstring parsing to better handle mixed alignment cstrings
-       src/MachOWriterExecutable.hpp: in -r mode, make all __cstrings aligned to section alignment
-
-
-2006-09-19      Nick Kledzik    <kledzik@apple.com>
-
-       src/MachOWriterExecutable.hpp: rework encoding of LC_SEGMENT_SPLIT_INFO
-
-
-2006-09-19      Nick Kledzik    <kledzik@apple.com>
-
-       src/Options.cpp: check for -search_paths_first in first pass
-
-
------ Tagged ld64-63
-
-2006-09-15      Nick Kledzik    <kledzik@apple.com>
-
-       src/Options.cpp: since the ld64 will repeatedly search an archive, and some project list archives
-               multiple times on command line to work with traditional linkers, automatically ignore duplicate libraries
-       unit-tests/test-cases/archive-duplicate: added test case
-
-
-2006-09-15      Nick Kledzik    <kledzik@apple.com>
-
-       src/Options.cpp: support -r -static
-       src/MachOWriterExecutable.hpp: support -r -static an don't generate LC_DYSYMTAB
-
-
-2006-09-14      Nick Kledzik    <kledzik@apple.com>
-
-       src/MachOWriterExecutable.hpp: in -r mode references to weak symbols should not create external relocations
-               as that can cause nmedit to errror later.
-
-
-2006-09-13      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4718189> ld64: Handle .objc_class_name exports specially
-       src/Options.cpp: add hack so that .objc_class_name_XXX in -exported_symbols_list imples _OBJC_CLASS_$_XXX
-       src/ld.cpp: add hack to supporess errors about .objc_class_name_XXX or _OBJC_CLASS_$_XXX being undefined
-
-
-2006-09-12      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4474172> Support -prebind when targeting ppc and OS < 10.4
-       src/Options.h: add splitSeg() and baseWritableAddress()
-       src/Options.cpp: Add support for -seg_addr_table and LD_SEG_ADDR_TABLE, and -prebind and LD_PREBIND.
-       src/src/MachOWriterExecutable.hpp: support split-seg and canonical prebound files to be generated
-
-
-2006-09-11      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4464904> Linking a dylib or binary from identical binaries should produce the same output
-       src/MachOWriterExecutable.hpp: set the timestamps to be constant
-
-
-2006-09-11      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4070025> Linker support for ordering all sections and symbols
-       src/Options.cpp: Add -order_file_statistics.  Allow architecture prefixes in order files
-       src/ld.cpp: Use fOptions.printOrderFileStatistics()
-
-
-2006-09-11      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/3894079> Support -sectorder
-       unit-tests/test-cases/order_file: added test case
-       src/ld.cpp: Implement order file support in Linker::sortAtoms()
-       src/Options.h: add Options.orderedSymbols()
-       src/Options.cpp: add parseOrderFile(), implement -order_file
-
-
-2006-09-07      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4637023> need -i for 64-bit (or equivalent)
-       <rdar://problem/4014529> Support -i for aliasing exported symbols
-       unit-tests/test-cases/alias-objects: added
-       unit-tests/test-cases/alias-command-line: added
-       src/ObjectFile.h: Added Atom::getOrdinal() as new way to sort atoms. Added ReaderOptions.fAliases
-       src/MachOReaderRelocatable.hpp: Added SymbolAliasAtom to handle multiple symbols to same address
-       src/MachOReaderArchive.hpp: implement Atom::getOrdinal() to space out atom ordinals across member objects
-       src/Options.cpp: support -i, -alias, -alias_list.  Move search of /Network/Library/Frameworks to after /System/Library/Frameworks
-       src/MachOWriterExecutable.hpp: pad out seg_info data.  Implement getOrdinal().
-       src/ObjectDump.cpp: call constructors directly instead of using make() wrapper
-
-
-2006-09-01      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4458878> Need the ability to tag libraries/plug-ins with security attributes
-       src/MachOReaderDylib.hpp: add warning if using -root_safe or -setuid_safe and link against dylib that is not
-       src/ObjectFile.h: add ReaderOption fRootSafe and fSetuidSafe
-       src/Options.cpp: handle -root_safe or -setuid_safe command line options
-       src/MachOWriterExecutable.hpp: set MH_ROOT_SAFE and MH_SETUID_SAFE flags
-
-
-2006-08-31      Nick Kledzik    <kledzik@apple.com>
-
-       src/ld.cpp: Add Linker::processDTrace() for processing dtrace static probes
-       src/OpaqueSection.hpp: renamed, add symbol name, add ability to add references
-       ld64.xcodeproj/project.pbxproj: remove SectCreate.cpp, add OpaqueSection.hpp
-
-
-2006-08-28      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4571042> Add convention for removing symbols at link time
-       <rdar://problem/3962731> Assembler -L option causes ld64 to split stubs
-       unit-tests/test-cases/special-labels: added test case
-       src/MachOReaderRelocatable.hpp: ignore L* labels, make l* labels as kSymbolTableNotIn
-
-
-2006-08-28      Nick Kledzik    <kledzik@apple.com>
-
-       src/lObjectFile.h: refactor isTargetUnbound() into getTargetBinding()
-       src/ld.cpp: create __dof section in final linked images from dtrace static probes
-       src/Architectures.hpp: add kDtraceProbe
-       src/Options.h/cpp: Add support for -dtrace
-       src/machochecker.cpp: support LC_SEGMENT_SPLIT_INFO
-       src/MachOWriterExecutable.hpp: support kDtraceProbe
-       src/MachOReaderRelocatable.hpp: suppport kDtraceProbe
-
-
-2006-08-25      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4701529> generate LC_SEGMENT_SPLIT_INFO for 10.5 or later dylibs
-       src/Options.h&.cpp: implement sharedRegionEligible() to control when LC_SEGMENT_SPLIT_INFO is added
-       src/MachOFileAbstraction.hpp: add macho_linkedit_data_command
-       src/MachOWriterExecutable.hpp: generate LC_SEGMENT_SPLIT_INFO load command and linkedit content
-
------ Tagged ld64-62
-
-2006-08-15      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4681062> wrong error message when symbol is found in unused indirect library
-       src/ld.cpp: remove indirect libraries if they are not re-exported
-       unit-tests/test-cases/indirect-dylib: added test case
-
-
-2006-08-15      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/3930461> alignment needs to be richer
-       src/ObjectFile.h: define ObjectFile::Alignment class for tracking rich alignment info
-       src/ld.cpp: modify SymbolTable::add() to work with new Alignment type
-       src/MachOReaderRelocatable.hpp: use new Alignment type. Remove alignAtLeast() and handleAnonymousNonLazyPointers()
-       src/MachOWriterExecutable.hpp: update for new Alignment type, use modulus when calculating layout address
-       src/ObjectDump.cpp: print richer Alignment info
-       unit-tests/test-cases/align-modulus: added test case
-
-
-2006-08-11      Nick Kledzik    <kledzik@apple.com>
-
-       remove OPEN_SOURCE conditionals around x86_64 support
-
-
-2006-07-31      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4654131> ld64 while linking cc1 [ when dead_strip is ON]
-       src/ld.cpp: Add ivar fAtomsWithUnresolvedReferences to track atoms not initially resolvable
-       unit-tests/test-cases/dead_strip-archive: added test case
-
-
-2006-07-31      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4656617> x86_64: instructions with immediate and rip-relative operands need to use new relocation types
-       src/MachOWriterExecutable.hpp: generate new reloc types in -r mode
-       src/MachOReaderRelocatable.hpp: parse new reloc types
-       unit-tests/test-cases/relocs-asm/relocs-asm.s: add test cases for new reloc type
-
-
-2006-07-18      Nick Kledzik    <kledzik@apple.com>
-
-       src/MachOReaderRelocatable.hpp: suppress warning about dwarf info parsing for one benign no-op case
-       the compiler emits when there are not functions in the __text section
-
-
-2006-07-17      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4634840> faster debug note generation
-       src/ld.cpp: rework collectDebugInfo() to produce all debug notes in one pass, intead of a
-       pass per .o file. Added timing info for collectDebugInfo() to -print_statistics
-       unit-tests/test-cases/dwarf-debug-notes-r/Makefile: add expliced -arch to ld -r
-       unit-tests/test-cases/dwarf-debug-notes-r/expected-stabs: alter for new debug notes order
-
-
-2006-07-17      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4623994> ld64 VSIZE is 1.18GB when building Finder ppc64
-       src/ld.cpp: fixed typo in createReader() that prevented dylibs from being unmapped
-
------ Tagged ld64-61.1
-
-2006-07-11      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4622049> ld64-61: gcc DejaGnu tests failing due to -arch followed by unknown architecture name
-       src/Options.cpp: map ppc750, ppc7400, ppc7450, and ppc970 to ppc. Improve error message
-
-2006-07-11      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4622769> If -arch is missing, rollover to ld_classic does not happen
-       src/Options.h: make gotoClassicLinker() public
-       src/ld.cpp: call gotoClassicLinker() if the inferred architecture is ppc or i386
-
------ Tagged ld64-61
-
-2006-06-29      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4606628> ld64 should be renamed to ld
-       src/Options.cpp: exec() ld_classic if -arch ppc or -arch i386 is seen
-       src/ld.cpp: alter version string
-       ld64.xcodeproj/project.pbxproj: change install location to /usr/bin/ld, add symlink from /usr/bin/ld64
-       doc/man/man1/ld.1: added
-
------ Tagged ld64-60
-
-2006-06-28      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4604539> Can't link large ppc64 program: ld64 says "bl out of range"
-       MachOWriterExecutable.hpp: fix branch island generation to work for weak_import functions
-       and properly chain together branch islands
-       MachOReaderRelocatable.hpp: improve performance of huge .o file reading by sorted references
-       only when done
-
-2006-06-28      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4603454> MySQL-36 fails to build with ld64-59
-       src/MachOReaderRelocatable.hpp: back out fix for 4585335
-       src/MachOWriterExecutable.hpp: back out fix for 4585335
-
-2006-06-27      Nick Kledzik    <kledzik@apple.com>
-
-       src/MachOReaderRelocatable.hpp: handle N_GSYM without ending :G() since that is how
-       dwarf debug notes are formed.
-
-2006-06-23      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4599239 objc class with no superclass causes bad undefined symbol
-       src/MachOReaderRelocatable.hpp: handle NULL superclass in objc_class
-       unit-tests/test-cases/relocs-objc/test.m: add case with no super class
-
-
-2006-06-23      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4313369> ld64 doesn't support variant linking -framework fw,_debug
-       src/Options.cpp: enhance findFramework() to support suffixes
-
------ Tagged ld64-59
-
-2006-06-22      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4596726> ld64 lost DWARF debug notes
-       src/MachOReaderRelocatable.hpp: add fHasUUID so kDebugInfoStabsUUID can be set later
-       unit-tests/test-cases/dwarf-debug-notes-r: added test case
-
-2006-06-21      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4567995> python 64-bit address miscalculation
-       src/MachOReaderRelocatable.hpp: change getTargetOffset() to sign extend the 32-bit value to 64-bits
-
-2006-06-21      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4535036> ld64 seems to offset things incorrectly when using -r
-       src/MachOWriterExecutable.hpp: in -r mode, virtual sections should not increment address
-
-
------ Tagged ld64-58
-
-2006-06-16      Nick Kledzik    <kledzik@apple.com>
-
-       src/rebase.cpp: fix page alignment problem
-       src/rebase.cpp: fix endianess problem with local non-lazy pointers
-
-2006-06-15      Nick Kledzik    <kledzik@apple.com>
-
-       src/rebase.cpp: fix to build in CurryWeed
-       ld64.xcodeproj/project.pbxproj: fix to build properly in CurryWeed
-
-2006-06-15      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4495309> Support .objc_class_name_* symbols
-       src/ObjectFile.h: Add kSymbolTableInAsAbsolute
-       src/MachOReaderRelocatable.hpp: synthesize references to required objc classes
-       src/MachOWriterExecutable.hpp: write objc_class_name as absolute symbol
-       unit-tests/test-cases/objc-references: added
-
-2006-06-15      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4484369> SECTION_ATTRIBUTES unset in ppc64 mach-o header
-       src/MachOWriterExecutable.hpp: add section attribute for sections with code
-
-2006-06-15      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4569407> ld64 bogus duplicate symbol name linking GNU libobjc
-       src/MachOReaderRelocatable.hpp: only special case Apple objc runtime objc classes
-
-2006-06-15      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4582999> x86_64: ".align" directive not honored
-       src/MachOReaderRelocatable.hpp: change code alignment to not depend on atom size
-
-2006-06-14      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4585335> jump table into middle of weak symbol causes error
-       src/MachOReaderRelocatable.hpp: create direct references to the interior of weak symbols
-       src/MachOWriterExecutable.hpp: do not error on absolute references to interior of weak symbols
-
-2006-06-13      Nick Kledzik    <kledzik@apple.com>
-
-       src/Options.cpp: allow -image_base as an alias for -seg1addr
-
-2006-06-13      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4585115> implement -d
-       src/Options.h: add fMakeTentativeDefinitionsReal
-       src/Options.cpp: set fMakeTentativeDefinitionsReal if -d option is found
-       src/MachOWriterExecutable.hpp: turn tentative into real definition if makeTentativeDefinitionsReal
-       unit-tests/test-cases/btentative-to-real: added test case
-
-2006-06-13      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4584355> implement -bundle_loader
-       src/Options.h: add fBundleLoader bit to DynamicLibraryOptions
-       src/Options.cpp: handle -bundle_loader
-       src/ld.cpp: pass fBundleLoader bit to MachOReaderDylib
-       src/MachOReaderDylib.hpp: support reading MH_EXECUTE files if fBundleLoader is set
-       src/MachOWriterExecutable.hpp: set bundle loader ordinal as EXECUTABLE_ORDINAL
-       unit-tests/test-cases/bundle_loader: added test case
-
-2006-06-12      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4583347> -syslibroot can cause "can't find ordinal for imported" error
-       src/MachOReaderDylib.hpp: in  Reader::reExports() compare install path in addition to load path
-
-
-2006-06-10      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4548935> Need rebasing tool
-       src/rebase.cpp: added
-       unit-tests/test-cases/rebase-basic: added
-       doc/man/man1/rebase.1: added
-       ld64.xcodeproj/project.pbxproj:  added rebase target.  changed all targets to build with dwarf
-
-
-2006-06-10      Nick Kledzik    <kledzik@apple.com>
-
-       src/machochecker.cpp: add some ppc reloc sanity checking
-
------ Tagged ld64-57
-
-2006-06-06      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4565088> ld64 is not adding a final '/' char on the initial directory-name SO stab debug map entry
-       ld.cpp: Change Linker::synthesizeStabs() to assure directory SO always has a trailing slash
-       unit-tests/test-cases/dwarf-debug-notes/expected-stabs: update with trailing /
-
-2006-06-06      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4572702> -sectcreate of a 0-byte section fails
-       MachOWriterExecutable.cpp: Don't error out on zero length segments
-       MachOWriterExecutable.cpp: For ppc64 reloc base address is the first writable segment iff
-        there is a writable segment >4GB from base address
-
-2006-06-04  Eric Christopher  <echristo@apple.com>
-
-       Radar 4560240
-       Radar 3964999
-       * src/ld.cpp (createReader): Fixed error message.
-       (resolve): Ditto.
-       (resolveFrom): Ditto.
-       (checkUndefines): Ditto.
-
------ Tagged ld64-56
-
-2006-05-23      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4558079> No debug notes for ObjC methods when linking with ld64
-       ld.cpp: don't limit debug notes to functions starting with underscore
-
-2006-05-22      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4556982> ld64 spends much time in mach_o::relocatable::Reader<x86_64>::findAtomByName
-       * src/MachOReaderRelocatable.hpp: add makeReferenceToSymbol() so that x86_64 does not need to do by-name lookups
-
-2006-05-22      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4535044> remove inferring warning
-       * ld.cpp: Remove "inferring" warning.  If a link failed and now arch was specifed add which arch was
-       inferred to error message
-
-2006-05-19      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4544001> ld64 does not honor -arch_multiple
-       * ld.cpp: If fOptions.printArchPrefix(), add architecture name to error message
-
-2006-05-19      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4555973> Support S_16BYTE_LITERALS section types
-       * src/MachOReaderRelocatable.hpp: support S_16BYTE_LITERALS
-       * src/MachOWriterExecutable.hpp: support S_16BYTE_LITERALS
-
-2006-05-19      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4548803> "warning can't parse dwarf compilation unit info" warnings building debug
-       * src/MachOReaderRelocatable.hpp: fix bugs in dwarf line table parsing
-
------ Tagged ld64-55
-
-2006-05-18      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4534339> Default the pagezero size to 4GB for x86-64
-       * src/Options.cpp: Chnage default the pagezero size to 4GB for x86-64
-
-2006-05-18      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4552825> x86_64 CarbonCore fails to link with "atom not found in symbolIndex"
-       * src/MachOWriterExecutable.hpp: in buildObjectFileFixups() don't call addObjectRelocs() on kNoFixUp references
-
-2006-05-18      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4553555> ld64: .section defaults to read-only
-       * src/MachOReaderRelocatable.hpp: default unknown segments to r/w
-
-2006-05-18      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4551990> -fvisibility=hidden causes crashes for x86_64
-       * src/MachOWriterExecutable.hpp: properly handle RIP relative tentative definitions
-
-2006-05-12      Nick Kledzik    <kledzik@apple.com>
-
-       * src/Architectures.hpp: add x86::kAbsolute32
-       * src/MachOReaderRelocatable.hpp: generate x86::kAbsolute32 for mdynamic-no-pic instructions
-       * src/MachOWriterExecutable.hpp: process x86::kAbsolute32 reference kind
-
------ Tagged ld64-54
-
-2006-05-11      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4545108> CF-393 failes to link for x86_64
-       * src/MachOWriterExecutable.cpp: fix sign extension for Rel32 relocs in Writer<x86_64>::fixUpReferenceRelocatable
-
-2006-05-11      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4501434> warning arch x86_64 not found using i386
-       * src/ld.cpp: remove hack to allow x86_64 to link against i386 dylibs
-
-
-2006-05-10      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4543754> x86_64: .objc_class_name symbol names scrambled
-       * src/MachOReaderRelocatable.hpp: properly compute alignment of __OBJC __class sections
-
-
-2006-05-08      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/3894083> Support -dead_strip
-       * src/Options.h/cpp: implement -why_load and -why_live.  Enable -dead_strip.
-       * src/MachOReaderArchive.hpp: implement -why_load
-       * src/MachOReaderRelocatable.hpp: suppress GCC_except_table* symbols in final output
-       * src/ld.cpp: implement dead code stripping
-       * unit-tests/test-cases/dead_strip: added
-
------ Tagged ld64-53
-
-2006-05-05      Nick Kledzik    <kledzik@apple.com>
-
-       * src/Options.cpp: make 10.4 be minimum OS version for newer architectures
-
-2006-05-05      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4147604> N_SO symbols in 64-bit builds have a zero address for n.n_value
-       * src/ld.cpp: for SO stabs, associate first and last atom in the SO range
-       * src/MachOWriterExecutable.hpp: use atom associated with SO stab to set ins n_value
-
-2006-05-05      Nick Kledzik    <kledzik@apple.com>
-
-       * MachOWriterExecutable.hpp: fix end FUN stab to have length of function
-
-
-2006-05-02      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4496250> 64-bit main executables should have 4GB zero page by default
-       * src/Opptions.cpp: change default pagezero_size to 4GB for ppc64
-       <rdar://problem/4492850> 64 bit: apps with -mdynamic-no-pic seg fault when page zero > 4GB
-       * src/MachOWriterExecutable.cpp: rework pagezero for ppc64 so that if any mdynamic-no-pic code
-       is found, the code is kept in the low 2GB, and a new segment is create to map away up to 4GB.
-
-2006-05-02      Nick Kledzik    <kledzik@apple.com>
-
-       * src/Opptions.cpp: remove warning about -stack_addr not specified.  Add warning if 32-bit stack
-       overlaps shared region
-
------ Tagged ld64-52.1
-
-2006-05-01      Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.cpp: rework handleAnonymousNonLazyPointers() to handle anl's in the middle
-       the __data section too.
-
------ Tagged ld64-52
-
-2006-04-28      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4513304> 64-bit: 9A152 TextEdit crashes in dlopen on bring-up
-       * src/MachOReaderRelocatable.cpp: rework anonymous non-lazy-pointer detection
-
-2006-04-28      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4528054> 64 Bit: Development build of ppc64 TextEdit gets confused about static variables
-       * src/MachOReaderRelocatable.cpp: mark non-lazy-pointer atoms as scopeTranslationUnit if targetting a static symbol
-
-
-
-2006-04-21      Nick Kledzik    <kledzik@apple.com>
-
-       * src/Options.cpp: fix default address for ppc64 custom stack
-       * src/MachOWriterExecutable.cpp: fix set up of ppc64 custom stack
-
-
-2006-04-14      Nick Kledzik    <kledzik@apple.com>
-
-       * src/Options.cpp: fix -sub_library processing to work it dylib is specifed with leaf name
-
------ Tagged ld64-51.1
-
-2006-04-13      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4513304> 64-bit: 9A152 TextEdit crashes in dlopen on bring-up
-       * src/MachOReaderRelocatable.hpp: when detecting anonymous non-lazy-pointers disqualify data
-       that points to static or global symbols
-       * src/ld.cpp: print version of ld64 in error messages
-
-
------ Tagged ld64-51
-
-2006-04-11      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4499168> exported symbols not properly stripped
-       * src/MachOReaderRelocatable.hpp: enable AnonymousAtom::setScope()
-
-2006-03-31      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4498391> ld64 fails when linking debug ppc64 HIToolbox
-       * src/MachOReaderRelocatable.hpp: handle anonymous non-lazy pointers encoded with local relocations
-       * src/MachOWriterExecutable.hpp: in -r mode, only generated INDIRECT_SYMBOL_LOCAL for non-lazy targets that
-
-
-2006-03-31      Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4496499> ld64 should remove generated file if link errors out
-       * src/MachOWriterExecutable.hpp: catch exceptions in Writer<A>::write(), delete output file, and rethrow
-
-
------ Tagged ld64-50
-
-
-2006-03-29      Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.hpp: synthesize .objc_class_name symbols
-       * src/MachOFileAbstraction.hpp: use strncpy for sect/seg names to zero fill trailing space
-
-2006-03-28      Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.hpp: fix spurious warning about dwarf line info
-
------ Tagged ld64-49.1
-
-2006-03-25      Nick Kledzik    <kledzik@apple.com>
-
-       * MachOWriterExecutable.hpp : don't complain about ppc64 dyld being based > 4GB
-
------ Tagged ld64-49
-
-2006-03-24     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOWriterExecutable.hpp: dyld is allowed to have synthesized non-lazy pointers
-       <rdar://problem/4488113> ld64 is after processing bad GSYM stabs
-       * src/MachOReaderRelocatable.hpp: if a GSYM is found that does not match any data symbol, suppress it
-
-2006-03-23     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOWriterExecutable.hpp: in Writer<x86>::fixUpReferenceFinal() fix when x86::kPointer is for an
-       external relocation
-
-2006-03-23     Nick Kledzik    <kledzik@apple.com>
-
-       * src/Options.cpp: change macosx-min-version to default to a per-architecture setting
-         add warning if -pagezero_size is not page aligned
-       * src/MachOWriterExecutable.hpp: properly handle external relocations for ppc64 with 4GB pagezero
-       * src/machochecker.cpp: sanity check relocation records
-
------ Tagged ld64-48
-
-2006-03-21     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4481406> 64bit: passing function pointer to another function passes the wrong function address
-       * src/MachOReaderRelocatable.hpp: when processing a non-lazy pointer to a static function, don't accidentally
-       match it to a STAB symbol.
-
-2006-03-21     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4180168> .eh symbols make up 13% of libstdc++'s stripped binary size
-       * src/ObjectFile.h: add ReaderOptions.fForFinalLinkedImage
-       * src/Options.cpp: setup ReaderOptions.fForFinalLinkedImage
-       * src/MachOReaderRelocatable.hpp: mark .eh symbols kSymbolTableNotIn when building final linked image
-
-2006-03-21     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4473742> ld64 does not parse optional second argument to -filelist
-       * unit-tests/test-cases/filelist: added
-       * src/Options.cpp: in Options::loadFileList() handle comma option
-
-
------ Tagged ld64-47.1
-
-
------ Tagged ld64-47
-
-
------ Tagged ld64-46
-
-2006-03-10     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4419505> ld64 should figure out architecture from .o files
-       * unit-tests/test-cases/auto-arch: added
-       * src/ld.cpp: added Linker::inferArchitecture() to scan .o files are infer architecture to link
-       * src/MachOReaderArchive.hpp: enhanced validFile() to look deeper into archive and really valdate
-       * src/MachOWriterExecutable.hpp: stop using fOptions.architecture()
-       * src/Options.cpp: stop defaulting to ppc64
-
-
-2006-03-09     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4465004> Need "intentionally left blank" dylib stubs
-       * unit-tests/include/common.makefile: add VALID_ARCHS
-       * unit-tests/run-all-unit-tests: set up VALID_ARCHS
-       * unit-tests/test-cases/blank-stubs: add test case
-       * src/ld.cpp: in addDylib(), detect and ignore blank stubs
-       * src/MachOReaderDylib.hpp: in constructor, handle blank stubs
-
-2006-03-09     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4471424> crash in stub with 2GB pagezero
-       * src/MachOWriterExecutable.hpp: StubAtom<ppc64> can't be no-pic if a large zero-page is used
-
-2006-03-06     Nick Kledzik    <kledzik@apple.com>
-
-       * src/Options.cpp: addSectionAlignment, warn if -sectalign alignment is not a power of two
-
------ Tagged ld64-45
-
-
-2006-03-06     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4466930> LP64/9A122: ld64: hang when trying to link DiscRecording framework
-       * src/Options.cpp: addSectionAlignment, warn on zero.  Use log2() for alignment conversion
-
-
------ Tagged ld64-44
-
-2006-03-04     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.hpp: fix again test for detection of anonymous non-lazy-pointer.
-       Error out if .o file contains old __DWARFA style dwarf.
-
-2006-03-02     Nick Kledzik    <kledzik@apple.com>
-
-       * src/ld.cpp: only re-map page aligned sub-parts of a fat file.  A conformat mmap() requires alignment.
-
------ Tagged ld64-43
-
-
-2006-03-02     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.hpp: <rdar://problem/4464370> tighten detection of anonymous non-lazy-pointer
-
------ Tagged ld64-42
-
-2006-02-28     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.hpp: fix x86 __IMPORT permissions for class Segment
-
-2006-02-28     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4461240> SWB: ld64-37 (can't resolve symbol ___dso_handle)
-       * src/MachOWriterExecutable.hpp: add class DsoHandleAtom
-
-2006-02-28     Nick Kledzik    <kledzik@apple.com>
-
-       * unit-tests/test-cases/literals-coalesce-alignment: added test case
-       * src/ld.cpp: when coalescing strings pick one with greater alignment
-       <rdar://problem/4458660> ld64: CG link failed because lo14 reference to anonymous non-lazy-pointer not aligned
-       * unit-tests/test-cases/relocs-c/test.c: tweak to fail like 4458660
-       * src/MachOReaderRelocatable.hpp: detect anonymous non-lazy-pointer and transform into real non-lazy-pointers
-
------ Tagged ld64-41
-
-2006-02-24     Nick Kledzik    <kledzik@apple.com>
-
-       * src/Options.cpp: Warning about -no_dead_strip_inits_and_terms and -i options.
-                                          Fix -weak-l option.
-
------ Tagged ld64-40
-
-2006-02-24     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4454698> Leopard9A113: ppc64 libstdc++.dylib initializer crashes in pthread_once
-       * unit-tests/test-cases/multiple-entry-points: added
-       * src/MachOReaderRelocatable.hpp: make sure that if there are multiple symbols with the same
-       address, that we properly make zero length atoms for all but last symbol
-
-2006-02-24     Nick Kledzik    <kledzik@apple.com>
-
-       * src/Options.cpp: <rdar://problem/4456093> ld64 doesn't realpath(3) B&I tracing paths
-
-2006-02-24     Nick Kledzik    <kledzik@apple.com>
-
-       * src/Options.cpp: <rdar://problem/4457078> 9A110: ld64 can't deal with section names >16 chars
-
-2006-02-23     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOWriterExecutable.hpp:  use vector.reserve() to minimize re-allocations
-       * src/Options.cpp: use vector.reserve() to minimize re-allocations
-       * src/MachOReaderRelocatable.hpp:  use vector.reserve() to minimize re-allocations
-       * src/MachOReaderDylib.hpp:  use vector.reserve() to minimize re-allocations
-       * src/ld.cpp:  use vector.reserve() to minimize re-allocations
-
-2006-02-23     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4455927> ld64 creates corrupt executables (and has malloc errors) with -headerpad option
-       * src/MachOWriterExecutable.hpp: Change LoadCommandsPaddingAtom<A>::setSize() to update fLargestAtomSize
-       * unit-tests/test-cases/header-pad: added
-
-2006-02-23     Nick Kledzik    <kledzik@apple.com>
-
-       <rdar://problem/4455192> ld64 creates invalid static executables
-       * src/MachOWriterExecutable.hpp: Change MachHeaderAtom<A>::copyRawContent() to create correct header
-       for static executables.  Change SymbolTableLoadCommandsAtom to skip LC_DYSYMTAB for static executables
-       * src/machochecker.cpp: Add tests that static executables are well formed
-       * unit-tests/test-cases/static-executable: added
-
-2006-02-22     Nick Kledzik    <kledzik@apple.com>
-
-       * src/Options.cpp: <rdar://problem/4453468> chnage printf on unknown arg to a throw
-
------ Tagged ld64-39
-
-2006-02-20     Nick Kledzik    <kledzik@apple.com>
-
-       * unit-tests/test-cases/read-only-relocs: added new test case
-       * src/MachOWriterExecutable.hpp: <rdar://problem/4448922> detect and error on relocs in read-only sections
-       * src/MachOReaderRelocatable.hpp: fix parsing of i386 absolute addressing relocs
-
-2006-02-20     Nick Kledzik    <kledzik@apple.com>
-
-       * unit-tests/test-cases/stabs-coalesce: added new test case
-       * src/ld.cpp.hpp: <rdar://problem/4449226> in collectStabs removed unused stabs
-
------ Tagged ld64-38
-
-2006-02-17     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOWriterExecutable.hpp: <rdar://problem/4434578> set correct n_sect field of stabs
-
-2006-02-15     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderArchive.hpp: <rdar://problem/4441920> with -all_load skip over both kinds of SYMDEFs
-       * unit-tests/test-cases/archive-basic/Makefile: add -all_load test case
-
------ Tagged ld64-37
-
-2006-02-13  Eric Christopher  <echristo@apple.com>
-
-       * src/MachOWriterExecutable.hpp (assignFileOffsets): Simplify. Add comments.
-       Adjust whitespace.
-
-2006-02-13     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOWriterExecutable.hpp: in Writer<x86>::fixUpReferenceRelocatable() fix kPCRel32 for external case
-
-2006-02-13     Nick Kledzik    <kledzik@apple.com>
-
-       * unit-tests/test-cases/zero-fill: added
-       * src/machochecker.cpp: check that S_ZEROFILL have no file offset
-       * src/MachOWriterExecutable.hpp: rework assignFileOffsets() to fix rdar://problem/4441145
-
-2006-02-12     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.hpp: <rdar://problem/4440880> fix use of first zero-length c-string in .o file
-
-2006-02-12     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.hpp: <rdar://problem/4440905> fix uninitialized fAlignment
-
-2006-02-12     Nick Kledzik    <kledzik@apple.com>
-
-       * unit-tests/test-cases/relocs-asm/relocs-asm.s: add pointer-diff cases
-       * src/Architectures.hpp: make size explicit in ppc/ppc64 kPointerDiff
-       * src/MachOReaderRelocatable.hpp: don't allow kPointerDiff64 for ppc (just ppc64)
-       * src/MachOWriterExecutable.cpp: set proper r_length for ld -r of kPointerDiff
-
------ Tagged ld64-36
-
-2006-02-08     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.cpp: rdar://problem/4438677 Handle when a .o file dwarf line info entries but no functions
-
-2006-02-08     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOWriterExecutable.cpp: Properly set address of first TEXT section
-       Keep S_COALESCED attribute for __eh_frame
-
-2006-02-08     Nick Kledzik    <kledzik@apple.com>
-
-       * src/ld.cpp: Temporarily turn allowable client errors into warnings
-       * unit-tests/test-cases/allowable-clientMakefile: Temporarily let warnings be ok for above
-       * src/MachOWriterExecutable.hpp: fix ld -r to not use external relocations for symbols make static
-
-2006-02-08     Nick Kledzik    <kledzik@apple.com>
-
-       * src/ld.cpp: A sibling in an umbrella can always link with its other siblings
-       * unit-tests/test-cases/allowable-client: add test case for above
-
-2006-02-08     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.hpp: support LOCAL non-lazy pointers to hidden symbols
-       * src/machochecker.cpp: verify indirect symbol table
-       * unit-tests/test-cases/private-non-lazy: added test case
-
-2006-02-07     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOWriterExecutable.hpp: fix calculation of file offsets in ld -r mode
-       * src/machochecker.cpp: verify segment file offsets are within file
-
------ Tagged ld64-35
-
-2006-02-06     Nick Kledzik    <kledzik@apple.com>
-
-       * ld.cpp: allow parent of sub-framework to link
-       * unit-tests/test-cases/allowable-client/Makefile: added cases for parent and clients of parent
-
-2006-02-04     Nick Kledzik    <kledzik@apple.com>
-
-       * unit-tests/test-cases/relocs-c/test.c:  added some array cases
-       * src/MachOReaderRelocatable.hpp: factor out makeReferenceToEH()
-       * src/MachOWriterExecutable.hpp: add initial support for non-lazy pointer synthesis
-
------ Tagged ld64-34
-
-2006-02-04     Nick Kledzik    <kledzik@apple.com>
-
-       * src/ld.cpp: <rdar://problem/4432917> fix -no_arch_warnings
-                                 <rdar://problem/4432932> fix -undefined warning
-                               Do BINCL/EINCL optimization for gfull stabs
-                               Implement "essential symbols" for stabs (-Sp)
-                               Fix allowable clients to only test on direct libraries
-       * src/MachOReaderRelocatable.hpp: support BINCL/EINCL stabs
-
-2006-02-03     Nick Kledzik    <kledzik@apple.com>
-
-       * src/machochecker.cpp: add code to check load command alignment
-       * src/MachOWriterExecutable.hpp: make load command alignment depend on architecture
-
-2006-02-03     Nick Kledzik    <kledzik@apple.com>
-
-       * unit-tests/test-cases/literals-coalesce: added
-       * src/MachOReaderRelocatable.hpp: assure all targets of low14 ppc relocs are at least 4-byte alignmented
-
------ Tagged ld64-33
-
-2006-02-02     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.hpp: properly coalesce 8-byte literals
-       * src/MachOWriterExecutable.hpp: support ppc64::kPointerDiff32
-
------ Tagged ld64-32
-
-2006-02-02     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.hpp: support anonymous zero fill atoms
-
-2006-02-02     Nick Kledzik    <kledzik@apple.com>
-
-       * src/ld.cpp: A weak definition is good enough, do not search archives for a non-weak one
-       * unit-tests/test-cases/archive-weak: add test case for above
-       * src/MachOReaderRelocatable.hpp: an atom should never have a by-name reference to itself
-       * src/Options.cpp: prevent .eh symbols from being exported via a -exported_symbols_list
-
-2006-02-01     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.hpp: Support -macosx_version_min 10.5
-
-2006-02-01     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.hpp: don't try to parse debug_line dwarf if no symboled atoms
-
------ Tagged ld64-31
-
-2006-02-01  Eric Christopher  <echristo@apple.com>
-
-       * unit-tests/test-cases/allow-stack-execute/Makefile: Move otool handling...
-       * unit-tests/include/common.makefile: ... here.
-       * unit-tests/bin/fail-if-stdin.pl: New.
-       * unit-tests/test-cases/no-uuid: Ditto.
-       * src/ld.cpp (Linker::) Add fCreateUUID.
-       (::Linker): Initialize.
-       (::collectStabs): Use. Set if dwarf or we have a UUID already.
-       (::writeOutput): Pass as argument to Writer::write along with option.
-       * src/Options.h (Option::emitUUID): Declare.
-       (Option::fEmitUUID): Ditto.
-       * src/Options.cpp (Option::emitUUID): New.
-       (parse): Handle -no_uuid.
-       * src/MachOReaderRelocatable (Reader::Reader): Handle LC_UUID.
-       * src/ExecutableFile.h (Writer::Write): Add createUUID boolean.
-       * src/MachOWriterExecutable: Add UUID forward declaration.
-       (fUUIDAtom): New.
-       (UUIDLoadCommandAtom): Emit LC_UUID if fEmit. New function emit. Size
-       to zero at start.
-       (Writer::writer): Add handle for LC_UUID. If createUUID emit LC_UUID.
-       (MachHeaderAtom::copyRawContent): Don't count a load command if its size is
-       0.
-       (UUIDLoadCommandAtom::copyRawContent): Depend on fEmit.
-
-
-2006-01-31     Nick Kledzik    <kledzik@apple.com>
-
-       * unit-tests/test-cases/dwarf-debug-notes : Added
-       * src/ld.cpp: don't generate debug note for .eh symbols
-       * src/MachOReaderRelocatable.hpp: make dwarf line info to atom matching faster and better
-
-2006-01-31     Nick Kledzik    <kledzik@apple.com>
-
-       * ld64.xcodeproj/project.pbxproj : Make buildable on Leopard
-       * src/MachOFileAbstraction.hpp: make buildable without latest cctools headers
-
-2006-01-31     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.hpp: better error message for bad relocs
-       * src/ObjectDump.cpp: add emacs tab settings
-       * src/SectCreate.h: ditto
-       * src/SectCreate.cpp: ditto
-       * src/machochecker.cpp: ditto
-       * src/ExecutableFile.h: ditto
-
-2006-01-30  Eric Christopher  <echristo@apple.com>
-
-       * src/ExecutableFile.h: Indent.
-
-2006-01-30     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.hpp: performance improvements
-       * src/ld.cpp: now that stubs are synthesized in write, don't need to special case anymore
-
-2006-01-30     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.hpp: fix parsing of pcc relocs
-       * unit-tests/test-cases/relocs-asm/relocs-asm.s: add test case for above
-
-2006-01-29     Nick Kledzik    <kledzik@apple.com>
-
-       * unit-tests/test-cases/weak_import: added test case
-       * src/ld.cpp: move code for weak_import mismatch to writer
-       * src/ObjectFile.h: remove ImportWeakness methods
-       * src/MachOReaderDylib.hpp: ditto
-       * src/SectCreate.cpp: ditto
-       * src/Architectures.hpp: add new ReferenceKinds for weak_imports
-       * src/MachOReaderRelocatable.hpp: implement new ReferenceKinds
-       * src/MachOWriterExecutable.hpp: handle new ReferenceKinds and weak_import mismatches
-
-2006-01-29     Nick Kledzik    <kledzik@apple.com>
-
-       * src/Options.cpp: verify -allow_stack_execute is only used on main executables
-
-2006-01-29     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.hpp: sync with latest dwarf reader from Geoff
-       * src/debugline.c: sync with latest dwarf reader from Geoff
-
-2006-01-27  Eric Christopher  <echristo@apple.com>
-
-       * src/ld.cpp (Linker::syntesizeStabs): Correct spelling. Update all uses.
-
-2006-01-27  Eric Christopher  <echristo@apple.com>
-
-       * src/Options.h (Options): Add hasExecutableStack, fExecutableStack.
-       * src/Options.cpp (Options::hasExecutableStack): New.
-       (Options::parse): Parse -allow_stack_execute.
-       * src/MachOWriterExecutable.hpp (MachHeaderAtom::copyRawContent):
-       Implement MH_ALLOW_STACK_EXECUTION.
-       * unit-tests/include/common.makefile (FAIL_IF_EMPTY): New.
-       * unit-tests/bin/fail-if-no-stdin.pl: New file.
-       * unit-tests/test-cases/allow-stack-execute: New directory.
-
-2006-01-27     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOFileAbstraction.hpp: rely on latest system headers
-       * src/MachOWriterExecutable.hpp: fix ppc stubs.
-               wrote new relocationNeededInFinalLinkedImage() to replace common code
-
-2006-01-27  Eric Christopher  <echristo@apple.com>
-
-       * src/ld.cpp (logTraceInfo): New.
-       (Linker::addArchive): Use.
-       (Linker::addDylib): Ditto.
-       * src/ObjectFile (ReaderOptions::fTraceOutputFile): New.
-       * src/MachOReaderArchive.hpp (Reader::Reader): Move trace
-       logging to Linker::addArchive.
-       * src/Options.cpp (parsePreCommandLineEnvironment): Check
-       LD_PRINT_FILE if tracing dylibs or archives.
-
-2006-01-26     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOWriterExecutable.hpp: handle NULL strings in SO debug notes
-
-2006-01-26     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOWriterExecutable.hpp: fix header padding calculation and thread state
-
-2006-01-26     Nick Kledzik    <kledzik@apple.com>
-
-       Rewrite all stabs processing.
-       Move sythesize of debug notes into ld.cpp
-
-2006-01-26     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOWriterExecutable.hpp: fix ppc and ppc64 stub relocs
-
-2006-01-25     Nick Kledzik    <kledzik@apple.com>
-
-       * ld64.xcodeproj/project.pbxproj: special case building in Curry
-
-2006-01-25     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOWriterExecutable.hpp: fix bugs in stub/lazy-pointer synthesis
-
-2006-01-24  Eric Christopher  <echristo@apple.com>
-
-       * src/ld.cpp (Linker::createReaders): Change logging title to XBS.
-       (Linker::addDylib): Ditto.
-       * src/MachOReaderArchive.hpp (Reader::Reader): Ditto.
-       * src/Options.h (fPrintOptions): New.
-       * src/Options.cpp (Options::Options): Initialize above.
-       (Options::checkForFile): Change logging title to XBS.
-       (Options::findFramework): Ditto.
-       (Options::parse): Add log for options.
-       (Options::parsePreCommandLineEnvironmentSettings): Add LD_TRACE_ARCHIVES,
-       LD_TRACE_DYLIBS, and LD_PRINT_OPTIONS.
-
-2006-01-24     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.hpp: better C++ eh parsing
-
-2006-01-23  Eric Christopher  <echristo@apple.com>
-
-       * unit-tests/bin/fail-if-exit-zero.pl: New.
-       * unit-tests/include/common.makefile (FAIL_IF_SUCCESS): Use.
-       * unit-tests/allowable-client: New test.
-       * src/ld.cpp (Linker::addDylib): Check allowable clients before adding dylib.
-       * src/Options.h (allowableClients): New.
-       (clientName): Ditto.
-       (fAllowableClients): Ditto.
-       (fClientName): Ditto.
-       * src/Options.cpp: Implement above.
-       (parse): Handle -allowable_client and -client_name.
-       * src/MachOReaderDylib.hpp (getAllowableClients): New.
-       (fAllowableClients): Ditto.
-       (Reader): Process LC_SUB_CLIENT load command.
-       * src/ObjectFile.h (parentUmbrella): New.
-       (getAllowableClients): New.
-       * src/MachOWriterExecutable.hpp (AllowableClientLoadCommandsAtom): New.
-
-2006-01-23     Nick Kledzik    <kledzik@apple.com>
-
-       * unit-tests/test-cases/archive-basic: added
-       * src/ld.cpp: fix shadowed local variable
-       * src/FileAbstraction.hpp: <rdar://problem/4417372> ld64 shouldn't inline when building debug
-
-2006-01-23     Nick Kledzik    <kledzik@apple.com>
-
-       * src/ld.cpp: fix symbol not found error message
-       * src/MachOReaderDylib.hpp: add logging to hash table
-       * src/MachOReaderRelocatable.hpp: enable stabs processing. Handle static functions with stubs
-                                                                       handle labeled cstrings.
-       * src/MachOWriterExecutable.hpp: properly suppress atoms not in symbol table. fix low14 error check.
-                                                                       add StubAtomHelper.
-       * unit-tests/test-cases/relocs-literals/test.c: add more interesting edge cases
-
-2006-01-17     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.hpp: tweaks to synthesizing debug notes
-
-2006-01-16     Nick Kledzik    <kledzik@apple.com>
-
-       * src/debugline.{sh}: added
-       * src/MachOReaderRelocatable.hpp: synthesize debug notes SOL from dwarf
-       * src/MachOWriterExecutable.hpp: fix lazy pointer section
-       * src/ObjectDump.hpp: Fix conditionalization
-       * unit-tests/test-cases/dwarf-strip: added
-
-2006-01-11     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.hpp: support Tiger crt1.o build with old ld64
-       * src/ObjectDump.hpp: Support -arch option
-
-2006-01-10     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOWriterExecutable.hpp: fix stubs for ppc64
-       * src/MachOFileAbstraction.hpp: fix typo for macho_routines
-       * ld64.xcodeproj/project.pbxproj: add machochecker target
-       * src/machochecker.cpp: new skeleton for checking mach-o file bit
-       * unit-tests/: Add support for running machochecker
-
-2006-01-10     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.hpp: warn if dwarf can't be parsed
-       * src/MachOReaderArchive.hpp: modTime for OSO stabs from archives is .a modTime
-
-2006-01-09     Nick Kledzik    <kledzik@apple.com>
-
-       * track modification time of .o files so that sythesized OSO stab will have it
-
-2006-01-09     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOFileAbstraction.hpp: add macho_uuid_command
-       * src/MachOWriterExecutable.cpp: add UUID load command to generated files
-
-2006-01-09     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderDylib.hpp: no longer keep dylib memory mapped
-       * src/ld.cpp: don't track dylib sizes because they are not longer memory mapped
-
-2006-01-05     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.hpp: support new relocations
-
-2006-01-05     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderDylib.hpp: support MH_DYLIB_STUB
-       * src/MachOReaderRelocatable.hpp: Add Geoff's comp unit extractor
-
-2006-01-05     Nick Kledzik    <kledzik@apple.com>
-
-       refactor: transform Atom::dontStripName() to getSymbolTableInclusion()
-       * src/ld.cpp: pass dyld_stub_binding_helper to writer
-       * src/MachOReaderRelocatable.hpp: update synthesized stabs
-         Ignore stubs and lazy pointers in .o files
-         Support initializers and terminators
-       * src/MachOWriterExecutable.hpp: synthesize stubs and lazy pointers as needed
-       * ld64.xcodeproj/project.pbxproj: change Release target to build with dwarf
-
-2006-01-03  Eric Christopher  <echristo@apple.com>
-
-       * src/Options.h (multipleDefinitionsInDylibs): Declare.
-       (overridingDefinitionInDependentDylib): Ditto.
-       (warnOnMultipleDefinitionsInObjectFiles): Ditto.
-       (multiplyDefined): Remove.
-       (multiplyDefinedUnused): Ditto.
-       (fMultiplyDefined): Ditto.
-       (fWarnOnMultiplyDefined): New.
-       (fMultiplyDefinedDynamic): Ditto.
-       * src/Options.cpp (Options::Options): Initialize above.
-       (overridingDefinitionInDependentDylib): New.
-       (multipleDefinitionsInDylibs): Ditto.
-       (warnOnMultipleDefinitionsInObjectFiles): Ditto.
-       (parse): Update comments. Fix parsing of -y option.
-       Update error message for -dead_strip. Parse above
-       options.
-
-2006-01-02     Nick Kledzik    <kledzik@apple.com>
-
-       * Refactor: move Atom::writeContent() to Writer
-
-2005-12-23     Nick Kledzik    <kledzik@apple.com>
-
-       * Reworked, simplify, and document test harness
-       * unit-tests/README: Added
-
-2005-12-23     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.hpp: fixes for Objective-C
-       * unit-tests/test-cases/relocs-objc: Added
-
-2005-12-22     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.hpp: fix check that next reloc is pair
-       * src/MachOReaderRelocatable.hpp: Add code to synthesize essential stabs from dwarf
-
-2005-12-21     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.hpp: Fix parsing of literal sections
-       * src/MachOWriterExecutable.hpp: Fix writing of literal sections
-       * unit-tests/test-cases/relocs-literals: Added
-
-2005-12-15  Eric Christopher  <echristo@apple.com>
-
-       * src/Options.h (enum Treatment): New.
-       (enum PICTreatment): Delete.
-       (enum VersionMin): New.
-       (prebind): Declare.
-       (macosxVersionMin): Ditto.
-       (multiplyDefined): Ditto.
-       (multiplyDefinedUnused): Ditto.
-       (setVersionMin): Ditto.
-       (setPICTreatment): Delete.
-       (setReadOnlyRelocTreatment): Ditto.
-       (picTreatment): Adjust return type.
-       (parseTreatment): New.
-       (fPrebind): Ditto.
-       (fVersionMin): Ditto.
-       (fPICTreatment): Change type.
-       (fMultiplyDefined): New.
-       (fMultiplyDefinedUnused): Ditto.
-       (fLimitUndefinedSymbols): Ditto.
-
-       * src/Options.cpp: Fix whitespace. Add comments on options.
-       (Options::Options): Add initializers for new variables.
-       (Options::prebind): New.
-       (Options::macosxVersionMin): Ditto.
-       (Options::parseTreatment): Ditto.
-       (Options::setVersionMin): Ditto.
-       (Options::setReadOnlyRelocTreatment): Delete.
-       (Options::setPICTreatment): Ditto.
-       (Options::Parse): Update for above. Add comments.
-
-2005-12-15     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.hpp: Add comments about dwarf
-
-2005-12-14     Nick Kledzik    <kledzik@apple.com>
-
-       * src/ELFFileAbstraction.hpp: Added
-       * src/ELFReaderRelocatable.hpp: Added
-       * Lot of fixes for new architecture
-       * Added __OPEN_SOURCE__ to "Preprocessor Macros" to disable new architecture support by default
-
-2005-12-13     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.hpp: check for S_ATTR_DEBUG and ignore those sections
-       * unit-tests/test-cases/dwarf-ignore: added
-
-2005-12-12     Nick Kledzik    <kledzik@apple.com>
-
-       * Added test harness and three initial tests:
-               relocs-asm, relocs-c, and hello-world
-
-2005-12-12     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOReaderRelocatable.hpp: Massive refactoring:
-               Now there are three Atom classes, Chopping into Atoms
-               is done on label boundaries or by knowledge of special
-               sections, Share lots of ppc/ppc64 code.
-       Stabs process code is temporarily disabled.
-
-2005-12-12     Nick Kledzik    <kledzik@apple.com>
-
-       * src/ObjectDump.cpp: Add command line options: -no_content, -stabs, -no_sort
-
-2005-12-11  Eric Christopher  <echristo@apple.com>
-
-       * src/Options.cpp: Reformat.
-       * src/Options.h: Ditto.
-
-2005-12-07  Eric Christopher  <echristo@apple.com>
-
-       * src/MachOReaderRelocatable.hpp (Atom::getAlignment):
-       When calculating alignment of an Atom, take into account
-       the alignment from which we pulled the Atom.
-
-2005-12-06     Nick Kledzik    <kledzik@apple.com>
-
-       * src/Options.cpp src/Options.h: Add design comments
-
-2005-12-05  Eric Christopher  <echristo@apple.com>
-
-       * src/ld.cpp (Linker::createWriter): Uncomment ppc64 and
-       i386 linkers.
-
-2005-12-05  Eric Christopher  <echristo@apple.com>
-
-       * ChangeLog: New file.
-
-2005-12-02     Nick Kledzik    <kledzik@apple.com>
-
-       * src/ObjectFile.h: Add design comments
-
-2005-11-30     Nick Kledzik    <kledzik@apple.com>
-
-       * Fix uses of __OPEN_SOURCE__
-
-2005-11-28     Nick Kledzik    <kledzik@apple.com>
-
-       * Refactor Atom to use getDefinitionKind()
-
-2005-11-21     Nick Kledzik    <kledzik@apple.com>
-
-       * src/MachOWriterExecutable.hpp: don't generate section for commons in -r mode
-
-2005-11-18     Nick Kledzik    <kledzik@apple.com>
-
-       * x86 tweaks
-
-2005-11-18     Nick Kledzik    <kledzik@apple.com>
-
-       * src/ObjectDump.cpp: make work with command line arguments
-
-2005-11-18     Nick Kledzik    <kledzik@apple.com>
-
-       * Massive rework to remove preprocessor conditionals and use templates
-
-2005-11-14     Nick Kledzik    <kledzik@apple.com>
-
-       * Created new Subversion repository for ld64 from cvs tag ld64-27.2
index 3dafedc40ee45e1ebfecb132df5713b5613a08a0..92deb13bd6780e5774ad7b4f1066c233ca512e5d 100644 (file)
@@ -1,4 +1,4 @@
-.Dd November 20, 2008
+.Dd November 10, 2010
 .Dt dyldinfo 1
 .Os Darwin
 .Sh NAME
@@ -7,12 +7,14 @@
 .Sh SYNOPSIS
 .Nm
 .Op Fl arch Ar arch-name 
+.Op Fl dylibs
 .Op Fl rebase
 .Op Fl bind
 .Op Fl weak_bind
 .Op Fl lazy_bind
 .Op Fl export
 .Op Fl opcodes
+.Op Fl function_starts
 .Ar file(s)
 .Sh DESCRIPTION
 Executables built for Mac OS X 10.6 and later have a new format for the
@@ -23,10 +25,12 @@ The options are as follows:
 .Bl -tag -width indent
 .It Fl arch Ar arch
 Only display the specified architecture.  Other architectures in a universal image are ignored.
+.It Fl dylibs
+Display the table of dylibs on which this image depends.
 .It Fl rebase
 Display the table of rebasing information.  Rebasing is what dyld does when an image is 
 not loaded at its preferred address.  Typically, this involves updating pointers in the __DATA
-segment which are point within the image. 
+segment which point within the image. 
 .It Fl bind
 Display the table of binding information.  These are the symbolic fix ups that dyld must
 do when an image is loaded.
@@ -41,6 +45,8 @@ functions in some external dylib.
 Display the table symbols which this image exports.
 .It Fl opcodes
 Display the low level opcodes used to encode all rebase and binding information.
+.It Fl function_starts
+Decodes the list of function start addresses.
 .El
 .Sh SEE ALSO
 .Xr otool 1
index b6363fc8fe012972ec40050a511488a1ee4dd665..d4d13294f356a13d25e0e2c6d9d3962c103896b3 100644 (file)
@@ -1,4 +1,4 @@
-.Dd December 15, 2008
+.Dd Sept 2, 2010
 .Dt ld 1
 .Os Darwin
 .Sh NAME
@@ -78,7 +78,7 @@ paths.
 .Ss Two-level namespace
 By default all references resolved to a dynamic library record the library to which 
 they were resolved. At runtime, dyld uses that information to directly resolve
-symobls.  The alternative is to use the -flat_namespace option.  With flat namespace,
+symbols.  The alternative is to use the -flat_namespace option.  With flat namespace,
 the library is not recorded.  At runtime, dyld will search each dynamic library in load
 order when resolving symbols. This is slower, but more like how other operating systems 
 resolve symbols. 
@@ -114,7 +114,7 @@ Merges object files to produce another mach-o object file with file type MH_OBJE
 .It Fl dylinker
 Produce a mach-o dylinker that has file type MH_DYLINKER.  Only used when building dyld.
 .It Fl dynamic
-The default.  Implied by -dynamiclib, -bundle, or -execute
+The default.  Implied by -dylib, -bundle, or -execute
 .It Fl static
 Produces a mach-o file that does not use the dyld.  Only used building the kernel. 
 .It Fl arch Ar arch_name
@@ -149,12 +149,18 @@ the first function in it is called.
 This is the same as listing a file name path to a shared library on the link line
 except that the linker will construct glue code so that the shared library is not 
 loaded until the first function in it is called.
+.It Fl upward-l Ns Ar x
+This is the same as the -lx but specifies that the dylib is an upward dependency. 
+.It Fl upward_library Ar path_to_library
+This is the same as listing a file name path to a library on the link line but also marks 
+the dylib as an upward dependency.
 .It Fl L Ns dir
 Add 
 .Ar dir 
 to the list of directories in which to search for libraries. 
 Directories specified with -L are searched in the order they appear on the command line
-and before the default search path.
+and before the default search path. In Xcode4 and later, there can be a space between
+the -L and directory.
 .It Fl Z
 Do not search the standard directories when searching for libraries and frameworks.
 .It Fl syslibroot Ar rootdir
@@ -162,10 +168,15 @@ Prepend
 .Ar rootdir 
 to all search paths when searching for libraries or frameworks.
 .It Fl search_paths_first
-By default the -lx and -weak-lx options first search for a file of the form `libx.dylib' in each directory
+This is now the default (in Xcode4 tools).  When processing -lx the linker now searches each directory 
+in its library search paths for `libx.dylib' then `libx.a' before the moving on to the next path 
+in the library search path.  
+.It Fl search_dylibs_first
+Changes the searching behavior for libraries.  The default is that when processing -lx the linker
+searches each directory in its library search paths for `libx.dylib' then `libx.a'.
+This option changes the behavior to first search for a file of the form `libx.dylib' in each directory
 in the library search path, then a file of the form `libx.a' is searched for in the library search paths.
-This option changes it so that in each path `libx.dylib' is searched for then `libx.a' before the 
-next path in the library search path is searched.
+This option restores the search behavior of the linker prior to Xcode4.
 .It Fl framework Ar name[,suffix]
 This option tells the linker to search for `name.framework/name' the framework search path.
 If the optional suffix is specified the framework is first searched for the name with the suffix and then without
@@ -181,13 +192,17 @@ This was previously done with a separate -sub_umbrella option.
 This is the same as the -framework name[,suffix] except that the linker will 
 construct glue code so that the framework is not 
 loaded until the first function in it is called.  You cannot directly access
-data or Objective-C classes in a frameworked linked this way.
+data or Objective-C classes in a framework linked this way.
+.It Fl upward_framework Ar name[,suffix]
+This is the same as the -framework name[,suffix] but also specifies that the 
+framework is an upward dependency.  
 .It Fl F Ns dir
 Add 
 .Ar dir
 to the list of directories in which to search for frameworks. 
 Directories specified with -F are searched in the order they appear on the command line
-and before the default search path.
+and before the default search path. In Xcode4 and later, there can be a space between
+the -F and directory.
 .It Fl all_load
 Loads all members of static archive libraries.
 .It Fl ObjC
@@ -231,7 +246,7 @@ any symbol in that section that are specified in the order file
 is moved to the start of its section and laid out in the same order as in the order file 
 .Ar file .
 Order files are text files with one symbol name per line.  Lines starting with a # are comments.
-A symbol name may be optionally preceded with its object file leafname and a colon (e.g. foo.o:_foo). 
+A symbol name may be optionally preceded with its object file leaf name and a colon (e.g. foo.o:_foo). 
 This is useful for static functions/data that occur in multiple files. 
 A symbol name may also be optionally preceded with the architecture (e.g. ppc:_foo or ppc:foo.o:_foo).
 This enables you to have one order file that works for multiple architectures. 
@@ -249,6 +264,11 @@ This is set to indicate the oldest Mac OS X version that that the output is to b
 a later version enables the linker to assumes features of that OS in the output file.  The format of
 .Ar version
 is a Mac OS X version number such as 10.4 or 10.5
+.It Fl ios_version_min Ar version
+This is set to indicate the oldest iOS version that that the output is to be used on.  Specifying
+a later version enables the linker to assumes features of that OS in the output file.  The format of
+.Ar version
+is an iOS version number such as 3.1 or 4.0
 .It Fl image_base Ar address
 Specifies the perferred load address for a dylib or bundle. The argument
 .Ar address
@@ -321,11 +341,11 @@ will cause a bus error if a NULL pointer is dereferenced.  The argument
 is a hexadecimal number with an optional leading 0x.  If  
 .Ar size
 is zero, the linker will not generate a page zero segment.  By default on 32-bit architectures the page zero size 
-is 4KB.  On 64-bit architectures, the default size if 4GB.  The ppc64 architecture has some special cases. Since Mac
+is 4KB.  On 64-bit architectures, the default size is 4GB.  The ppc64 architecture has some special cases. Since Mac
 OS X 10.4 did not support 4GB page zero programs, the default page zero size for ppc64 will be 4KB unless 
 -macosx_version_min is 10.5 or later.  Also, the -mdynamic-no-pic codegen model for ppc64 will only work if the
 code is placed in the lower 2GB of the address space, so the if the linker detects any such code, the page zero
-size is set to 4KB and then a new unredable trailing segment is created after the code, filling up the lower 4GB.
+size is set to 4KB and then a new unreadable trailing segment is created after the code, filling up the lower 4GB.
 .It Fl stack_size Ar size
 Specifies the maximum stack size for the main thread in a program.  Without this option a program has a 8MB stack.
 The argument
@@ -353,7 +373,7 @@ dynamic libraries the bundle was linked with.
 Don't turn private external (aka visibility=hidden) symbols into static symbols, 
 but rather leave them as private external in the resulting object file.
 .It Fl d
-Force definition of common symbols.  That is, transform tentative defintions into real definitions.
+Force definition of common symbols.  That is, transform tentative definitions into real definitions.
 .El
 .Ss Options that control symbol resolution
 .Bl -tag
@@ -391,6 +411,11 @@ The specified
 is added to the list of global symbols names that will not remain as global symbols in the output file.  This 
 option can be used multiple times.  For short lists, this can be more convenient than creating a file and using 
 -unexported_symbols_list.
+.It Fl reexported_symbols_list Ar file
+The specified 
+.Ar filename 
+contains a list of symbol names that are implemented in a dependent dylib and should be re-exported
+through the dylib being created. 
 .It Fl alias Ar symbol_name Ar alternate_symbol_name
 Create an alias named 
 .Ar alternate_symbol_name
@@ -432,7 +457,7 @@ Specifies how commons (aka tentative definitions) are resolved with respect to d
 ignore_dylibs, use_dylibs, error.  The default is ignore_dylibs which means the linker will turn a tentative
 definition in an object file into a real definition and not even check dylibs for conflicts.  The dylibs
 option means the linker should check linked dylibs for definitions and use them to replace tentative definitions 
-from object files.  The error option means the linker should issu an error whenever a tentative definition in an
+from object files.  The error option means the linker should issue an error whenever a tentative definition in an
 object file conflicts with an external symbol in a linked dylib.  See also -warn_commons.
 .El
 .Ss Options for introspecting the linker
@@ -463,7 +488,7 @@ Do not put debug information (STABS or DWARF) in the output file.
 .It Fl x
 Do not put non-global symbols in the output file's symbol table. Non-global symbols are useful when debugging and
 getting symbol names in back traces, but are not used at runtime. If -x is used with -r
-non-global symbol names are not removed, but instead replaced with a unique, duumy name
+non-global symbol names are not removed, but instead replaced with a unique, dummy name
 that will be automatically removed when linked into a final linked image.  This
 allows dead code stripping, which uses symbols to break up code and data, to
 work properly and provides the security of having source symbol names removed.
@@ -488,6 +513,10 @@ Prints the version of the linker.
 Normally when targeting Mac OS X 10.6, the linker will generate compact information 
 in the __LINKEDIT segment.
 This option causes the linker to instead produce traditional relocation information.
+.It Fl allow_heap_execute
+Normally i386 main executables will be marked so that the Mac OS X 10.7 and later kernel 
+will only allow pages with the x-bit to execute instructions. This option overrides that
+behavior and allows instructions on any page to be run.
 .It Fl no_eh_labels
 Normally in -r mode, the linker produces .eh labels on all FDEs in the __eh_frame section.
 This option suppresses those labels.  Those labels are not needed by the Mac OS X 10.6
@@ -497,13 +526,23 @@ When producing a final linked image, the linker processes the __eh_frame section
 produces an __unwind_info section. Most FDE entries in the __eh_frame can be represented
 by a 32-bit value in the __unwind_info section.  The option issues a warning for 
 any function whose FDE cannot be expressed in the compact unwind format.
+.It Fl warn_weak_exports
+Issue a warning if the resulting final linked image contains weak external symbols. Such
+symbols require dyld to do extra work at launch time to coalesce those symbols.
+.It Fl objc_gc_compaction
+Marks the Objective-C image info in the final linked image with the bit that says that the  
+code was built to work the compacting garbage collection.
+.It Fl objc_gc
+Verifies all code was compiled with -fobjc-gc or -fobjc-gc-only.
+.It Fl objc_gc_only
+Verifies all code was compiled with -fobjc-gc-only.
 .It Fl dead_strip_dylibs
 Remove dylibs that are unreachable by the entry point or exported symbols. That is,  
 suppresses the generation of load command commands for dylibs which supplied no
 symbols during the link. This option should not be used when linking against a dylib which 
 is required at runtime for some indirect reason such as the dylib has an important initializer.
 .It Fl allow_sub_type_mismatches
-Normally the linker consisders different cpu-subtype for ARM (e.g. armv4t and armv6) to be different
+Normally the linker considers different cpu-subtype for ARM (e.g. armv4t and armv6) to be different
 different architectures that cannot be mixed at build time.  This option relaxes that requirement,
 allowing you to mix object files compiled for different ARM subtypes.
 .It Fl no_uuid
@@ -522,7 +561,13 @@ Only used when creating a dynamic library.
 .It Fl sub_umbrella Ar framework_name
 The specified framework will be re-exported.  Only used when creating a dynamic library. 
 .It Fl allowable_client Ar name
-Restricts what can link against the dynamic library being created.  
+Restricts what can link against the dynamic library being created.  By default any code 
+can link against any dylib. But if a dylib is supposed to be private to a small
+set of clients, you can formalize that by adding a -allowable_client for each client.
+If a client is libfoo.1.dylib its -allowable_client name would be "foo".  If a
+client is Foo.framework its -allowable_client name would be "Foo".  For the degenerate
+case where you want no one to ever link against a dylib, you can set the 
+-allowable_client to "!".  
 .It Fl client_name Ar name
 Enables a bundle to link against a dylib that was built with -allowable_client.  
 The name specified must match one of the -allowable_client names specified when the dylib was created.
@@ -601,11 +646,11 @@ driver when it is invoked with multiple -arch arguments.
 Specifies that hints should be added to the resulting binary that can help speed up runtime binding by dyld as long as the 
 libraries being linked against have not changed.
 .It Fl dot Ar path
-Create a file a file at the specified path containing a graph of symbol dependencies.  The .dot file can be viewed in GraphViz.
+Create a file at the specified path containing a graph of symbol dependencies.  The .dot file can be viewed in GraphViz.
 .It Fl keep_relocs
 Add section based relocation records to a final linked image.  These relocations are ignored at runtime by dyld.
 .It Fl warn_stabs
-Print a warning when the linker cannot do a BINCL/EINCL optimzation because the compiler put a bad stab symbol inside
+Print a warning when the linker cannot do a BINCL/EINCL optimization because the compiler put a bad stab symbol inside
 a BINCL/EINCL range.
 .It Fl warn_commons
 Print a warning whenever the a tentative definition in an object file is found and a external symbol by the same name
@@ -614,7 +659,7 @@ in a header file.
 .It Fl read_only_stubs
 [i386 only] Makes the __IMPORT segment of a final linked images read-only.  This option makes a program slightly more
 secure in that the JMP instructions in the i386 fast stubs cannot be easily overwritten by malicious code.  The downside
-is the dyld must use mprotect() to temporily make the segment writable while it is binding the stubs. 
+is the dyld must use mprotect() to temporarily make the segment writable while it is binding the stubs. 
 .It Fl slow_stubs
 [i386 only]  Instead of using single JMP instruction stubs, the linker creates code in the __TEXT segment which 
 calls through a lazy pointer in the __DATA segment.  
@@ -626,6 +671,22 @@ is linked such that _malloc is interposable, then calls to malloc() from within
 stub and could potentially indirected to an alternate malloc.  If libSystem.dylib were built without making _malloc 
 interposable then if _malloc was interposed at runtime, calls to malloc from with libSystem would be missed 
 (not interposed) because they would be direct calls.
+.It Fl no_function_starts
+By default the linker creates a compress table of function start addresses in the LINKEDIT of
+final linked image.  This option disables that behavior.
+.It Fl no_version_load_command
+By default the linker creates a load command in final linked images that contains the -macosx_version_min.
+This option disables that behavior.
+.It Fl no_objc_category_merging
+By default when producing final linked image, the linker will optimize Objective-C classes by merging
+any categories on a class into the class.  Both the class and its categories must be defined in the image
+being linked for the optimization to occur.  Using this option disables that behavior.
+.It Fl object_path_lto Ar filename
+When performing Link Time Optimization (LTO) and a temporary mach-o object file is needed, if this
+option is used, the temporary file will be stored at the specified path and remain after the link
+is complete.  Without the option, the linker picks a path and deletes the object file before the linker 
+tool completes, thus tools such as the debugger or dsymutil will not be able to access the DWARF debug
+info in the temporary object file.
 .El
 .Ss Obsolete Options
 .Bl -tag
@@ -663,7 +724,7 @@ This is now the default so does not need to be specified.
 .It Fl multi_module
 Multi-modules in dynamic libraries have been ignored at runtime since Mac OS X 10.4.0.  This option is obsolete.
 .It Fl no_dead_strip_inits_and_terms
-The linker never dead strips initialzation and termination routines.  They are considered "roots" of the dead strip graph.
+The linker never dead strips initialization and termination routines.  They are considered "roots" of the dead strip graph.
 .It Fl A Ar basefile
 Obsolete incremental load format.  This option is obsolete.
 .It Fl b
@@ -691,7 +752,7 @@ is used.  This was previously used to debug where an undefined symbol was used,
 automatically prints out all usages.  The -why_live option can also be used to display what kept 
 a symbol from being dead striped.  This option is obsolete.
 .It Fl Y Ar number
-Used to control how many occurances of each symbol specifed with -y would be shown.  This option is obsolete.
+Used to control how many occurrences of each symbol specified with -y would be shown.  This option is obsolete.
 .It Fl nomultidefs
 Only used when linking an umbrella framework.  Sets the MH_NOMULTIDEFS bit in the mach_header.  The MH_NOMULTIDEFS
 bit has been obsolete since Mac OS X 10.4.  This option is obsolete.
index 9c5493ce42417c0a7b9242cf21a165103b07f840..cfb54eb2827276bf86b089560ec5647603d73f28 100644 (file)
@@ -19,6 +19,7 @@
                                F96904890A4333AC00B77D2A /* PBXTargetDependency */,
                                F9EA73970974999B008B4F1D /* PBXTargetDependency */,
                                F9B693890EC4D28C00076912 /* PBXTargetDependency */,
+                               F9F9AD68116D58AF0028EFAB /* PBXTargetDependency */,
                        );
                        name = "unit-tests";
                        productName = "unit-tests";
 /* Begin PBXBuildFile section */
                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 */; };
                F97F5029070D0BB200B9FCD7 /* ld.1 in copy man page */ = {isa = PBXBuildFile; fileRef = F97F5028070D0BB200B9FCD7 /* ld.1 */; };
+               F98498A310AE2159009E9878 /* compact_unwind.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9BA963310A2545C0097A440 /* compact_unwind.cpp */; };
+               F98498A410AE2159009E9878 /* got.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9AB1063107D380700E54C9E /* got.cpp */; };
+               F9849E3610B38EF5009E9878 /* order_file.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9849E3410B38EF5009E9878 /* order_file.cpp */; };
+               F984A38210BB4B0D009E9878 /* branch_island.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F984A38010BB4B0D009E9878 /* branch_island.cpp */; };
+               F989D30D106826020014B60C /* OutputFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F989D30B106826020014B60C /* OutputFile.cpp */; };
                F9A3DDD30ED762E400C590B9 /* PruneTrie.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9A3DDD20ED762E400C590B9 /* PruneTrie.cpp */; };
                F9A3DE1E0ED7738300C590B9 /* prune_trie.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = F9A3DE0F0ED76D1900C590B9 /* prune_trie.h */; };
+               F9A4DB9110F816FF00BD8423 /* objc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9A4DB8F10F816FF00BD8423 /* objc.cpp */; };
+               F9AA44DC1294885F00CB8390 /* branch_shim.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9AA44DA1294885F00CB8390 /* branch_shim.cpp */; };
+               F9AA65111051BD2B003E3539 /* stubs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9AA65101051BD2B003E3539 /* stubs.cpp */; };
+               F9AA65891051E750003E3539 /* macho_relocatable_file.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9AA65871051E750003E3539 /* macho_relocatable_file.cpp */; };
+               F9AA65DD1051EC4A003E3539 /* archive_file.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9AA65D71051EC4A003E3539 /* archive_file.cpp */; };
+               F9AA65DE1051EC4A003E3539 /* lto_file.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9AA65D91051EC4A003E3539 /* lto_file.cpp */; };
+               F9AA65DF1051EC4A003E3539 /* macho_dylib_file.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9AA65DB1051EC4A003E3539 /* macho_dylib_file.cpp */; };
+               F9AA6786105700C2003E3539 /* opaque_section_file.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9AA6784105700C2003E3539 /* opaque_section_file.cpp */; };
+               F9AA67B610570C41003E3539 /* dtrace_dof.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9AA67B510570C41003E3539 /* dtrace_dof.cpp */; };
+               F9AA687C10572E27003E3539 /* InputFiles.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9AA687A10572E27003E3539 /* InputFiles.cpp */; };
+               F9AA69B610583C0C003E3539 /* SymbolTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9AA69B410583C0C003E3539 /* SymbolTable.cpp */; };
+               F9AA69C110583E19003E3539 /* Resolver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9AA69BF10583E19003E3539 /* Resolver.cpp */; };
+               F9AA6FF910618CD2003E3539 /* macho_relocatable_file.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9AA65871051E750003E3539 /* macho_relocatable_file.cpp */; };
+               F9AE20FF1107D1440007ED5D /* dylibs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9AE20FD1107D1440007ED5D /* dylibs.cpp */; };
+               F9AE23291109015E0007ED5D /* lto_file.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9AA65D91051EC4A003E3539 /* lto_file.cpp */; };
                F9B1A2640A3A563E00DA8FAB /* rebase.1 in install man page */ = {isa = PBXBuildFile; fileRef = F9B1A2580A3A448800DA8FAB /* rebase.1 */; };
                F9B670120DDA17E800E6D0DA /* UnwindDump.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9B670110DDA17E800E6D0DA /* UnwindDump.cpp */; };
                F9B813850EC2657800F94C13 /* unwinddump.1 in install man page */ = {isa = PBXBuildFile; fileRef = F9B813810EC2653000F94C13 /* unwinddump.1 */; };
                F9BA51650ECE58C800D1D62E /* dyldinfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9BA515B0ECE58AA00D1D62E /* dyldinfo.cpp */; };
+               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 */; };
                F9EA72D5097454FF008B4F1D /* machochecker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9EA72D4097454FF008B4F1D /* machochecker.cpp */; };
@@ -61,7 +84,7 @@
 /* Begin PBXBuildRule section */
                F9E8D4BD07FCAF2000FD5801 /* PBXBuildRule */ = {
                        isa = PBXBuildRule;
-                       compilerSpec = com.apple.compilers.gcc;
+                       compilerSpec = com.apple.compilers.llvm.clang.1_0;
                        fileType = sourcecode.c;
                        isEditable = 1;
                        outputFiles = (
@@ -69,7 +92,7 @@
                };
                F9E8D4BE07FCAF2A00FD5801 /* PBXBuildRule */ = {
                        isa = PBXBuildRule;
-                       compilerSpec = com.apple.compilers.gcc;
+                       compilerSpec = com.apple.compilers.llvm.clang.1_0;
                        fileType = sourcecode.cpp;
                        isEditable = 1;
                        outputFiles = (
                        remoteGlobalIDString = F9EA72CA097454A6008B4F1D;
                        remoteInfo = machocheck;
                };
+               F9F9AD67116D58AF0028EFAB /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = F9023C3006D5A227001BBF46 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = F9BA51600ECE58BE00D1D62E;
+                       remoteInfo = dyldinfo;
+               };
 /* End PBXContainerItemProxy section */
 
 /* Begin PBXCopyFilesBuildPhase section */
 /* End PBXCopyFilesBuildPhase section */
 
 /* Begin PBXFileReference section */
-               3DA587190ACC53BE0015C432 /* LTOReader.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = LTOReader.hpp; path = src/ld/LTOReader.hpp; sourceTree = "<group>"; };
                C02A29DE0953B26E001FB8C1 /* ChangeLog */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = ChangeLog; sourceTree = "<group>"; };
                F9023C3906D5A23E001BBF46 /* ld */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ld; sourceTree = BUILT_PRODUCTS_DIR; };
-               F9023C3E06D5A254001BBF46 /* ExecutableFile.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ExecutableFile.h; path = src/ld/ExecutableFile.h; sourceTree = "<group>"; };
                F9023C3F06D5A254001BBF46 /* ld.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ld.cpp; path = src/ld/ld.cpp; sourceTree = "<group>"; };
-               F9023C4106D5A254001BBF46 /* ObjectFile.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ObjectFile.h; path = src/ld/ObjectFile.h; sourceTree = "<group>"; };
+               F92D9C2710657AAB00FF369B /* stub_x86_64_classic.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_x86_64_classic.hpp; sourceTree = "<group>"; };
                F933D9460929277C0083EAC8 /* FileAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = FileAbstraction.hpp; path = src/abstraction/FileAbstraction.hpp; sourceTree = "<group>"; };
                F933D9470929277C0083EAC8 /* MachOFileAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = MachOFileAbstraction.hpp; path = src/abstraction/MachOFileAbstraction.hpp; sourceTree = "<group>"; };
                F933DC37092A82480083EAC8 /* Architectures.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Architectures.hpp; path = src/ld/Architectures.hpp; sourceTree = "<group>"; };
-               F933E3CC092E84250083EAC8 /* MachOReaderDylib.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = MachOReaderDylib.hpp; path = src/ld/MachOReaderDylib.hpp; sourceTree = "<group>"; };
-               F933E3CD092E84250083EAC8 /* MachOReaderRelocatable.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = MachOReaderRelocatable.hpp; path = src/ld/MachOReaderRelocatable.hpp; sourceTree = "<group>"; };
-               F933E3CE092E84250083EAC8 /* MachOWriterExecutable.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = MachOWriterExecutable.hpp; path = src/ld/MachOWriterExecutable.hpp; sourceTree = "<group>"; };
+               F93CB246116E69EB003233B8 /* tlvp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tlvp.cpp; sourceTree = "<group>"; };
+               F93CB247116E69EB003233B8 /* tlvp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tlvp.h; sourceTree = "<group>"; };
                F971EED306D5ACF60041D381 /* ObjectDump */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ObjectDump; sourceTree = BUILT_PRODUCTS_DIR; };
                F971EED706D5AD240041D381 /* ObjectDump.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ObjectDump.cpp; path = src/other/ObjectDump.cpp; sourceTree = "<group>"; };
                F97F5028070D0BB200B9FCD7 /* ld.1 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.man; name = ld.1; path = doc/man/man1/ld.1; sourceTree = "<group>"; };
-               F98D26850AA779BD00416316 /* OpaqueSection.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = OpaqueSection.hpp; path = src/ld/OpaqueSection.hpp; sourceTree = "<group>"; };
-               F99F63CE0D99A291007F5394 /* ArchiveReader.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ArchiveReader.hpp; path = src/ld/ArchiveReader.hpp; sourceTree = "<group>"; };
+               F984963310AB9318009E9878 /* stub_ppc_classic.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_ppc_classic.hpp; sourceTree = "<group>"; };
+               F9849E3410B38EF5009E9878 /* order_file.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = order_file.cpp; sourceTree = "<group>"; };
+               F9849E3510B38EF5009E9878 /* order_file.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = order_file.h; sourceTree = "<group>"; };
+               F984A13B10B614CF009E9878 /* stub_arm_classic.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_arm_classic.hpp; sourceTree = "<group>"; };
+               F984A38010BB4B0D009E9878 /* branch_island.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = branch_island.cpp; sourceTree = "<group>"; };
+               F984A38110BB4B0D009E9878 /* branch_island.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = branch_island.h; sourceTree = "<group>"; };
+               F989D0391062E6350014B60C /* stub_x86_64.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_x86_64.hpp; sourceTree = "<group>"; };
+               F989D30B106826020014B60C /* OutputFile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = OutputFile.cpp; path = src/ld/OutputFile.cpp; sourceTree = "<group>"; };
+               F989D30C106826020014B60C /* OutputFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OutputFile.h; path = src/ld/OutputFile.h; sourceTree = "<group>"; };
+               F989D3AA10684F5B0014B60C /* LinkEdit.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = LinkEdit.hpp; path = src/ld/LinkEdit.hpp; sourceTree = "<group>"; };
+               F989D44B10694F2E0014B60C /* LinkEditClassic.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = LinkEditClassic.hpp; path = src/ld/LinkEditClassic.hpp; sourceTree = "<group>"; };
+               F989D7E91072DEC20014B60C /* HeaderAndLoadCommands.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = HeaderAndLoadCommands.hpp; path = src/ld/HeaderAndLoadCommands.hpp; sourceTree = "<group>"; };
                F9A3DDCA0ED762B700C590B9 /* libprunetrie.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libprunetrie.a; sourceTree = BUILT_PRODUCTS_DIR; };
                F9A3DDD20ED762E400C590B9 /* PruneTrie.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PruneTrie.cpp; path = src/other/PruneTrie.cpp; sourceTree = "<group>"; };
                F9A3DE0F0ED76D1900C590B9 /* prune_trie.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = prune_trie.h; path = src/other/prune_trie.h; sourceTree = "<group>"; };
+               F9A4DB8F10F816FF00BD8423 /* objc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = objc.cpp; sourceTree = "<group>"; };
+               F9A4DB9010F816FF00BD8423 /* objc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = objc.h; sourceTree = "<group>"; };
+               F9AA44DA1294885F00CB8390 /* branch_shim.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = branch_shim.cpp; sourceTree = "<group>"; };
+               F9AA44DB1294885F00CB8390 /* branch_shim.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = branch_shim.h; sourceTree = "<group>"; };
+               F9AA5FCC103F5CD1003E3539 /* ld.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ld.hpp; path = src/ld/ld.hpp; sourceTree = "<group>"; };
+               F9AA650D1051BD2B003E3539 /* make_stubs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = make_stubs.h; sourceTree = "<group>"; };
+               F9AA650F1051BD2B003E3539 /* stub_arm.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_arm.hpp; sourceTree = "<group>"; };
+               F9AA65101051BD2B003E3539 /* stubs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = stubs.cpp; sourceTree = "<group>"; };
+               F9AA65871051E750003E3539 /* macho_relocatable_file.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = macho_relocatable_file.cpp; sourceTree = "<group>"; };
+               F9AA65881051E750003E3539 /* macho_relocatable_file.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = macho_relocatable_file.h; sourceTree = "<group>"; };
+               F9AA65D71051EC4A003E3539 /* archive_file.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = archive_file.cpp; sourceTree = "<group>"; };
+               F9AA65D81051EC4A003E3539 /* archive_file.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = archive_file.h; sourceTree = "<group>"; };
+               F9AA65D91051EC4A003E3539 /* lto_file.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lto_file.cpp; sourceTree = "<group>"; };
+               F9AA65DA1051EC4A003E3539 /* lto_file.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lto_file.h; sourceTree = "<group>"; };
+               F9AA65DB1051EC4A003E3539 /* macho_dylib_file.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = macho_dylib_file.cpp; sourceTree = "<group>"; };
+               F9AA65DC1051EC4A003E3539 /* macho_dylib_file.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = macho_dylib_file.h; sourceTree = "<group>"; };
+               F9AA6784105700C2003E3539 /* opaque_section_file.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = opaque_section_file.cpp; sourceTree = "<group>"; };
+               F9AA6785105700C2003E3539 /* opaque_section_file.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = opaque_section_file.h; sourceTree = "<group>"; };
+               F9AA67B410570C41003E3539 /* dtrace_dof.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dtrace_dof.h; sourceTree = "<group>"; };
+               F9AA67B510570C41003E3539 /* dtrace_dof.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dtrace_dof.cpp; sourceTree = "<group>"; };
+               F9AA687A10572E27003E3539 /* InputFiles.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = InputFiles.cpp; path = src/ld/InputFiles.cpp; sourceTree = "<group>"; };
+               F9AA687B10572E27003E3539 /* InputFiles.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = InputFiles.h; path = src/ld/InputFiles.h; sourceTree = "<group>"; };
+               F9AA69B410583C0C003E3539 /* SymbolTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SymbolTable.cpp; path = src/ld/SymbolTable.cpp; sourceTree = "<group>"; };
+               F9AA69B510583C0C003E3539 /* SymbolTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SymbolTable.h; path = src/ld/SymbolTable.h; sourceTree = "<group>"; };
+               F9AA69BF10583E19003E3539 /* Resolver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Resolver.cpp; path = src/ld/Resolver.cpp; sourceTree = "<group>"; };
+               F9AA69C010583E19003E3539 /* Resolver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Resolver.h; path = src/ld/Resolver.h; sourceTree = "<group>"; };
+               F9AB1063107D380700E54C9E /* got.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = got.cpp; sourceTree = "<group>"; };
+               F9AB1064107D380700E54C9E /* got.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = got.h; sourceTree = "<group>"; };
+               F9AE20FD1107D1440007ED5D /* dylibs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dylibs.cpp; sourceTree = "<group>"; };
+               F9AE20FE1107D1440007ED5D /* dylibs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dylibs.h; sourceTree = "<group>"; };
                F9B1A2580A3A448800DA8FAB /* rebase.1 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.man; name = rebase.1; path = doc/man/man1/rebase.1; sourceTree = "<group>"; };
                F9B670080DDA176100E6D0DA /* unwinddump */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = unwinddump; sourceTree = BUILT_PRODUCTS_DIR; };
                F9B670110DDA17E800E6D0DA /* UnwindDump.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UnwindDump.cpp; path = src/other/unwinddump.cpp; sourceTree = "<group>"; };
                F9B813BF0EC27C6700F94C13 /* MachOTrie.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = MachOTrie.hpp; path = src/abstraction/MachOTrie.hpp; sourceTree = "<group>"; };
                F9BA515B0ECE58AA00D1D62E /* dyldinfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dyldinfo.cpp; path = src/other/dyldinfo.cpp; sourceTree = "<group>"; };
                F9BA51610ECE58BE00D1D62E /* dyldinfo */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dyldinfo; sourceTree = BUILT_PRODUCTS_DIR; };
+               F9BA8A7E1096150F0097A440 /* stub_x86_classic.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_x86_classic.hpp; sourceTree = "<group>"; };
+               F9BA8A7F1096150F0097A440 /* stub_x86.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_x86.hpp; sourceTree = "<group>"; };
+               F9BA955C10A233000097A440 /* huge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = huge.cpp; sourceTree = "<group>"; };
+               F9BA955D10A233000097A440 /* huge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = huge.h; sourceTree = "<group>"; };
+               F9BA963310A2545C0097A440 /* compact_unwind.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = compact_unwind.cpp; sourceTree = "<group>"; };
+               F9BA963410A2545C0097A440 /* compact_unwind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = compact_unwind.h; 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>"; };
                        name = Products;
                        sourceTree = "<group>";
                };
+               F9AA650B1051BD2B003E3539 /* passes */ = {
+                       isa = PBXGroup;
+                       children = (
+                               F984A38010BB4B0D009E9878 /* branch_island.cpp */,
+                               F984A38110BB4B0D009E9878 /* branch_island.h */,
+                               F9AA44DA1294885F00CB8390 /* branch_shim.cpp */,
+                               F9AA44DB1294885F00CB8390 /* branch_shim.h */,
+                               F9849E3410B38EF5009E9878 /* order_file.cpp */,
+                               F9849E3510B38EF5009E9878 /* order_file.h */,
+                               F9BA963310A2545C0097A440 /* compact_unwind.cpp */,
+                               F9BA963410A2545C0097A440 /* compact_unwind.h */,
+                               F9AA67B410570C41003E3539 /* dtrace_dof.h */,
+                               F9AA67B510570C41003E3539 /* dtrace_dof.cpp */,
+                               F9BA955C10A233000097A440 /* huge.cpp */,
+                               F9BA955D10A233000097A440 /* huge.h */,
+                               F9AB1063107D380700E54C9E /* got.cpp */,
+                               F9AB1064107D380700E54C9E /* got.h */,
+                               F93CB246116E69EB003233B8 /* tlvp.cpp */,
+                               F93CB247116E69EB003233B8 /* tlvp.h */,
+                               F9AE20FD1107D1440007ED5D /* dylibs.cpp */,
+                               F9AE20FE1107D1440007ED5D /* dylibs.h */,
+                               F9A4DB8F10F816FF00BD8423 /* objc.cpp */,
+                               F9A4DB9010F816FF00BD8423 /* objc.h */,
+                               F9AA650C1051BD2B003E3539 /* stubs */,
+                       );
+                       name = passes;
+                       path = src/ld/passes;
+                       sourceTree = "<group>";
+               };
+               F9AA650C1051BD2B003E3539 /* stubs */ = {
+                       isa = PBXGroup;
+                       children = (
+                               F9AA650D1051BD2B003E3539 /* make_stubs.h */,
+                               F9AA65101051BD2B003E3539 /* stubs.cpp */,
+                               F9AA650F1051BD2B003E3539 /* stub_arm.hpp */,
+                               F984A13B10B614CF009E9878 /* stub_arm_classic.hpp */,
+                               F9BA8A7F1096150F0097A440 /* stub_x86.hpp */,
+                               F9BA8A7E1096150F0097A440 /* stub_x86_classic.hpp */,
+                               F989D0391062E6350014B60C /* stub_x86_64.hpp */,
+                               F92D9C2710657AAB00FF369B /* stub_x86_64_classic.hpp */,
+                               F984963310AB9318009E9878 /* stub_ppc_classic.hpp */,
+                       );
+                       path = stubs;
+                       sourceTree = "<group>";
+               };
+               F9AA65861051E750003E3539 /* parsers */ = {
+                       isa = PBXGroup;
+                       children = (
+                               F9AA6784105700C2003E3539 /* opaque_section_file.cpp */,
+                               F9AA6785105700C2003E3539 /* opaque_section_file.h */,
+                               F9AA65D71051EC4A003E3539 /* archive_file.cpp */,
+                               F9AA65D81051EC4A003E3539 /* archive_file.h */,
+                               F9AA65D91051EC4A003E3539 /* lto_file.cpp */,
+                               F9AA65DA1051EC4A003E3539 /* lto_file.h */,
+                               F9AA65DB1051EC4A003E3539 /* macho_dylib_file.cpp */,
+                               F9AA65DC1051EC4A003E3539 /* macho_dylib_file.h */,
+                               F9AA65871051E750003E3539 /* macho_relocatable_file.cpp */,
+                               F9AA65881051E750003E3539 /* macho_relocatable_file.h */,
+                       );
+                       name = parsers;
+                       path = src/ld/parsers;
+                       sourceTree = "<group>";
+               };
                F9B8137E0EC2651200F94C13 /* doc */ = {
                        isa = PBXGroup;
                        children = (
                F9B813AD0EC27B8500F94C13 /* ld */ = {
                        isa = PBXGroup;
                        children = (
+                               F9AA69BF10583E19003E3539 /* Resolver.cpp */,
+                               F9AA69C010583E19003E3539 /* Resolver.h */,
+                               F9AA69B410583C0C003E3539 /* SymbolTable.cpp */,
+                               F9AA69B510583C0C003E3539 /* SymbolTable.h */,
+                               F9AA687A10572E27003E3539 /* InputFiles.cpp */,
+                               F9AA687B10572E27003E3539 /* InputFiles.h */,
+                               F9AA5FCC103F5CD1003E3539 /* ld.hpp */,
                                F9023C3F06D5A254001BBF46 /* ld.cpp */,
-                               F933DC37092A82480083EAC8 /* Architectures.hpp */,
-                               F99F63CE0D99A291007F5394 /* ArchiveReader.hpp */,
-                               F933E3CD092E84250083EAC8 /* MachOReaderRelocatable.hpp */,
-                               F933E3CC092E84250083EAC8 /* MachOReaderDylib.hpp */,
-                               F933E3CE092E84250083EAC8 /* MachOWriterExecutable.hpp */,
-                               3DA587190ACC53BE0015C432 /* LTOReader.hpp */,
-                               F9023C3E06D5A254001BBF46 /* ExecutableFile.h */,
-                               F9023C4106D5A254001BBF46 /* ObjectFile.h */,
-                               F98D26850AA779BD00416316 /* OpaqueSection.hpp */,
                                F9C0D48A06DD1E1B001C7193 /* Options.cpp */,
                                F9C0D48B06DD1E1B001C7193 /* Options.h */,
+                               F989D30B106826020014B60C /* OutputFile.cpp */,
+                               F989D30C106826020014B60C /* OutputFile.h */,
+                               F989D7E91072DEC20014B60C /* HeaderAndLoadCommands.hpp */,
+                               F989D3AA10684F5B0014B60C /* LinkEdit.hpp */,
+                               F989D44B10694F2E0014B60C /* LinkEditClassic.hpp */,
+                               F9AA650B1051BD2B003E3539 /* passes */,
+                               F9AA65861051E750003E3539 /* parsers */,
+                               F933DC37092A82480083EAC8 /* Architectures.hpp */,
                                F9EA7582097882F3008B4F1D /* debugline.c */,
                                F9EA7583097882F3008B4F1D /* debugline.h */,
                        );
                        isa = PBXNativeTarget;
                        buildConfigurationList = F933D91B09291AC90083EAC8 /* Build configuration list for PBXNativeTarget "ld" */;
                        buildPhases = (
-                               0B12F6A50CE39466008ABCAE /* build configure.h */,
+                               F9E8DB4D11921594007B4D6A /* make config.h */,
                                F9023C3606D5A23E001BBF46 /* Sources */,
                                F9023C3706D5A23E001BBF46 /* Frameworks */,
                                F97F5025070D0B6300B9FCD7 /* copy man page */,
 /* Begin PBXProject section */
                F9023C3006D5A227001BBF46 /* Project object */ = {
                        isa = PBXProject;
+                       attributes = {
+                               ORGANIZATIONNAME = "Apple Inc.";
+                       };
                        buildConfigurationList = F933D92309291AC90083EAC8 /* Build configuration list for PBXProject "ld64" */;
                        compatibilityVersion = "Xcode 2.4";
+                       developmentRegion = English;
                        hasScannedForEncodings = 0;
+                       knownRegions = (
+                               English,
+                               Japanese,
+                               French,
+                               German,
+                       );
                        mainGroup = F9023C2C06D5A227001BBF46;
                        productRefGroup = F9023C3A06D5A23E001BBF46 /* Products */;
                        projectDirPath = "";
 /* End PBXProject section */
 
 /* Begin PBXShellScriptBuildPhase section */
-               0B12F6A50CE39466008ABCAE /* build configure.h */ = {
+               F96D5367094A2754008E9EE8 /* ShellScript */ = {
                        isa = PBXShellScriptBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
                        );
                        inputPaths = (
                        );
-                       name = "build configure.h";
                        outputPaths = (
-                               "$(DERIVED_FILE_DIR)/configure.h",
                        );
                        runOnlyForDeploymentPostprocessing = 0;
-                       shellPath = /bin/bash;
-                       shellScript = "if [ -f /Developer/usr/local/include/llvm-c/lto.h ]; then\n\techo \"#define LTO_SUPPORT 1\" > ${DERIVED_FILE_DIR}/configure.h\n\techo \"-Wl,-lazy_library,/Developer/usr/lib/libLTO.dylib\" > ${DERIVED_FILE_DIR}/linker_opts\nelse\n\techo \"#undef LTO_SUPPORT\" > ${DERIVED_FILE_DIR}/configure.h\n\techo \"\" > ${DERIVED_FILE_DIR}/linker_opts\nfi\n";
+                       shellPath = /bin/csh;
+                       shellScript = "# Let tests set MACOSX_DEPLOYMENT_TARGET as they need\nunsetenv MACOSX_DEPLOYMENT_TARGET\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;
                };
-               F96D5367094A2754008E9EE8 /* ShellScript */ = {
+               F9E8DB4D11921594007B4D6A /* make config.h */ = {
                        isa = PBXShellScriptBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
                        );
                        inputPaths = (
                        );
+                       name = "make config.h";
                        outputPaths = (
+                               "$(DERIVED_FILE_DIR)/configure.h",
                        );
                        runOnlyForDeploymentPostprocessing = 0;
-                       shellPath = /bin/csh;
-                       shellScript = "# Let tests set MACOSX_DEPLOYMENT_TARGET as they need\nunsetenv MACOSX_DEPLOYMENT_TARGET\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";
+                       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";
                        showEnvVarsInLog = 0;
                };
 /* End PBXShellScriptBuildPhase section */
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               F9023C4E06D5A272001BBF46 /* ld.cpp in Sources */,
                                F9C0D4BD06DD28D2001C7193 /* Options.cpp in Sources */,
+                               F9023C4E06D5A272001BBF46 /* ld.cpp in Sources */,
+                               F9AA65891051E750003E3539 /* macho_relocatable_file.cpp in Sources */,
+                               F9AA65DD1051EC4A003E3539 /* archive_file.cpp in Sources */,
+                               F9AA65DE1051EC4A003E3539 /* lto_file.cpp in Sources */,
+                               F9AA65DF1051EC4A003E3539 /* macho_dylib_file.cpp in Sources */,
                                F9EA7584097882F3008B4F1D /* debugline.c in Sources */,
+                               F9AA687C10572E27003E3539 /* InputFiles.cpp in Sources */,
+                               F9AA69B610583C0C003E3539 /* SymbolTable.cpp in Sources */,
+                               F9AA69C110583E19003E3539 /* Resolver.cpp in Sources */,
+                               F989D30D106826020014B60C /* OutputFile.cpp in Sources */,
+                               F9AA65111051BD2B003E3539 /* stubs.cpp in Sources */,
+                               F9AA6786105700C2003E3539 /* opaque_section_file.cpp in Sources */,
+                               F9AA67B610570C41003E3539 /* dtrace_dof.cpp in Sources */,
+                               F98498A310AE2159009E9878 /* compact_unwind.cpp in Sources */,
+                               F98498A410AE2159009E9878 /* got.cpp in Sources */,
+                               F9BA955E10A233000097A440 /* huge.cpp in Sources */,
+                               F9849E3610B38EF5009E9878 /* order_file.cpp in Sources */,
+                               F984A38210BB4B0D009E9878 /* branch_island.cpp in Sources */,
+                               F9A4DB9110F816FF00BD8423 /* objc.cpp in Sources */,
+                               F9AE20FF1107D1440007ED5D /* dylibs.cpp in Sources */,
+                               F93CB248116E69EB003233B8 /* tlvp.cpp in Sources */,
+                               F9AA44DC1294885F00CB8390 /* branch_shim.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               F9AA6FF910618CD2003E3539 /* macho_relocatable_file.cpp in Sources */,
+                               F9AE23291109015E0007ED5D /* lto_file.cpp in Sources */,
                                F933E3D9092E855B0083EAC8 /* ObjectDump.cpp in Sources */,
                                F9EA75BC09788857008B4F1D /* debugline.c in Sources */,
                        );
                        target = F9EA72CA097454A6008B4F1D /* machocheck */;
                        targetProxy = F9EA73960974999B008B4F1D /* PBXContainerItemProxy */;
                };
+               F9F9AD68116D58AF0028EFAB /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = F9BA51600ECE58BE00D1D62E /* dyldinfo */;
+                       targetProxy = F9F9AD67116D58AF0028EFAB /* PBXContainerItemProxy */;
+               };
 /* End PBXTargetDependency section */
 
 /* Begin XCBuildConfiguration section */
                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 = NO;
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                GCC_MODEL_TUNING = G5;
                                GCC_OPTIMIZATION_LEVEL = 0;
+                               GCC_PREPROCESSOR_DEFINITIONS = DEBUG;
                                GCC_TREAT_WARNINGS_AS_ERRORS = YES;
                                GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO;
                                GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
                                GCC_WARN_MISSING_PARENTHESES = YES;
                                GCC_WARN_NON_VIRTUAL_DESTRUCTOR = NO;
                                GCC_WARN_PEDANTIC = NO;
-                               GCC_WARN_SHADOW = NO;
+                               GCC_WARN_SHADOW = YES;
                                GCC_WARN_SIGN_COMPARE = YES;
                                GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
                                GCC_WARN_UNINITIALIZED_AUTOS = NO;
                                LINKER_DISPLAYS_MANGLED_NAMES = NO;
                                MACOSX_DEPLOYMENT_TARGET = "";
                                OTHER_CPLUSPLUSFLAGS = "$(OTHER_CPLUSPLUSFLAGS)";
-                               OTHER_LDFLAGS = "@$(DERIVED_FILE_DIR)/linker_opts";
+                               OTHER_LDFLAGS = "-Wl,-lazy_library,/Developer/usr/lib/libLTO.dylib";
                                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)";
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                GCC_DYNAMIC_NO_PIC = YES;
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
-                               GCC_MODEL_TUNING = G5;
                                GCC_OPTIMIZATION_LEVEL = 3;
-                               GCC_PREPROCESSOR_DEFINITIONS = "$(GCC_PREPROCESSOR_DEFINITIONS_$(RC_RELEASE))";
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "$(GCC_PREPROCESSOR_DEFINITIONS_QUOTED_FOR_TARGET_1)",
+                                       NDEBUG,
+                                       "$(GCC_PREPROCESSOR_DEFINITIONS_$(RC_RELEASE))",
+                               );
+                               GCC_PREPROCESSOR_DEFINITIONS_QUOTED_FOR_TARGET_1 = "LD_VERS='\"ld64-$(RC_ProjectSourceVersion)\"'";
                                GCC_TREAT_WARNINGS_AS_ERRORS = NO;
                                GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO;
                                GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
                                INSTALL_PATH = /usr/bin;
                                OTHER_CPLUSPLUSFLAGS = "$(OTHER_CPLUSPLUSFLAGS)";
                                OTHER_LDFLAGS = (
-                                       "-Wl,-no_pie",
-                                       "@$(DERIVED_FILE_DIR)/linker_opts",
+                                       "-Wl,-lazy_library,/Developer/usr/lib/libLTO.dylib",
                                        "-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;
                                GCC_MODEL_TUNING = G5;
                                GCC_OPTIMIZATION_LEVEL = 0;
-                               HEADER_SEARCH_PATHS = "$(DEVELOPER_DIR)/usr/local/include";
+                               GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+                               GCC_WARN_ABOUT_RETURN_TYPE = YES;
+                               GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
+                               GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
+                               GCC_WARN_SHADOW = YES;
+                               GCC_WARN_UNUSED_FUNCTION = YES;
+                               GCC_WARN_UNUSED_VALUE = YES;
+                               GCC_WARN_UNUSED_VARIABLE = YES;
+                               HEADER_SEARCH_PATHS = (
+                                       "$(SRCROOT)/src/ld",
+                                       "$(DEVELOPER_DIR)/usr/local/include",
+                               );
                                INSTALL_PATH = "$(HOME)/bin";
                                OTHER_LDFLAGS = "-Wl,-lazy_library,/Developer/usr/lib/libLTO.dylib";
                                OTHER_REZFLAGS = "";
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                GCC_MODEL_TUNING = G5;
                                GCC_OPTIMIZATION_LEVEL = s;
-                               HEADER_SEARCH_PATHS = "$(DEVELOPER_DIR)/usr/local/include";
+                               GCC_PREPROCESSOR_DEFINITIONS = NDEBUG;
+                               HEADER_SEARCH_PATHS = (
+                                       "$(SRCROOT)/src/ld",
+                                       "$(DEVELOPER_DIR)/usr/local/include",
+                               );
                                INSTALL_PATH = "$(HOME)/bin";
                                OTHER_LDFLAGS = "-Wl,-lazy_library,/Developer/usr/lib/libLTO.dylib";
                                OTHER_REZFLAGS = "";
                        };
                        name = Release;
                };
+               F9849FF810B5DE8E009E9878 /* Release-assert */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+                       };
+                       name = "Release-assert";
+               };
+               F9849FF910B5DE8E009E9878 /* Release-assert */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = YES;
+                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               PRODUCT_NAME = all;
+                               ZERO_LINK = NO;
+                       };
+                       name = "Release-assert";
+               };
+               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)";
+                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+                               GCC_DYNAMIC_NO_PIC = YES;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               GCC_OPTIMIZATION_LEVEL = 3;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "$(GCC_PREPROCESSOR_DEFINITIONS_QUOTED_FOR_TARGET_1)",
+                                       "$(GCC_PREPROCESSOR_DEFINITIONS_$(RC_RELEASE))",
+                               );
+                               GCC_PREPROCESSOR_DEFINITIONS_QUOTED_FOR_TARGET_1 = "LD_VERS='\"ld64-$(RC_ProjectSourceVersion)\"'";
+                               GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+                               GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO;
+                               GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
+                               GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+                               GCC_WARN_ABOUT_POINTER_SIGNEDNESS = NO;
+                               GCC_WARN_ABOUT_RETURN_TYPE = YES;
+                               GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
+                               GCC_WARN_EFFECTIVE_CPLUSPLUS_VIOLATIONS = NO;
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
+                               GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
+                               GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
+                               GCC_WARN_MISSING_PARENTHESES = YES;
+                               GCC_WARN_NON_VIRTUAL_DESTRUCTOR = NO;
+                               GCC_WARN_PEDANTIC = NO;
+                               GCC_WARN_SHADOW = NO;
+                               GCC_WARN_SIGN_COMPARE = YES;
+                               GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
+                               GCC_WARN_UNINITIALIZED_AUTOS = NO;
+                               GCC_WARN_UNKNOWN_PRAGMAS = YES;
+                               GCC_WARN_UNUSED_FUNCTION = YES;
+                               GCC_WARN_UNUSED_LABEL = YES;
+                               GCC_WARN_UNUSED_PARAMETER = NO;
+                               GCC_WARN_UNUSED_VALUE = YES;
+                               GCC_WARN_UNUSED_VARIABLE = YES;
+                               HEADER_SEARCH_PATHS = (
+                                       "$(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",
+                                       "-Wl,-exported_symbol,__mh_execute_header",
+                               );
+                               PREBINDING = NO;
+                               PRODUCT_NAME = ld;
+                               SECTORDER_FLAGS = "";
+                               STRIP_INSTALLED_PRODUCT = YES;
+                               STRIP_STYLE = debugging;
+                               VALID_ARCHS = "x86_64 i386 ppc";
+                               VERSIONING_SYSTEM = "apple-generic";
+                               WARNING_CFLAGS = "-Wall";
+                       };
+                       name = "Release-assert";
+               };
+               F9849FFB10B5DE8E009E9878 /* Release-assert */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = NO;
+                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_PREPROCESSOR_DEFINITIONS = "$(GCC_PREPROCESSOR_DEFINITIONS_$(RC_RELEASE))";
+                               HEADER_SEARCH_PATHS = "";
+                               INSTALL_PATH = /usr/bin;
+                               OTHER_LDFLAGS = "-Wl,-exported_symbol,__mh_execute_header";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = rebase;
+                               STRIP_INSTALLED_PRODUCT = YES;
+                               STRIP_STYLE = debugging;
+                               VALID_ARCHS = "i386 ppc x86_64";
+                       };
+                       name = "Release-assert";
+               };
+               F9849FFC10B5DE8E009E9878 /* Release-assert */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = NO;
+                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
+                               HEADER_SEARCH_PATHS = "";
+                               INSTALL_PATH = /usr/bin;
+                               OTHER_LDFLAGS = "-Wl,-exported_symbol,__mh_execute_header";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = unwinddump;
+                               STRIP_INSTALLED_PRODUCT = YES;
+                               STRIP_STYLE = debugging;
+                       };
+                       name = "Release-assert";
+               };
+               F9849FFD10B5DE8E009E9878 /* Release-assert */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = YES;
+                               DEBUG_INFORMATION_FORMAT = dwarf;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_OPTIMIZATION_LEVEL = s;
+                               GCC_PREPROCESSOR_DEFINITIONS = NDEBUG;
+                               HEADER_SEARCH_PATHS = (
+                                       "$(SRCROOT)/src/ld",
+                                       "$(DEVELOPER_DIR)/usr/local/include",
+                               );
+                               INSTALL_PATH = "$(HOME)/bin";
+                               OTHER_LDFLAGS = "-Wl,-lazy_library,/Developer/usr/lib/libLTO.dylib";
+                               OTHER_REZFLAGS = "";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = ObjectDump;
+                               WARNING_CFLAGS = (
+                                       "-Wmost",
+                                       "-Wno-four-char-constants",
+                                       "-Wno-unknown-pragmas",
+                               );
+                       };
+                       name = "Release-assert";
+               };
+               F9849FFE10B5DE8E009E9878 /* Release-assert */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = YES;
+                               DEBUG_INFORMATION_FORMAT = dwarf;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               GCC_MODEL_TUNING = G5;
+                               HEADER_SEARCH_PATHS = "";
+                               INSTALL_PATH = "$(HOME)/bin";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = machocheck;
+                       };
+                       name = "Release-assert";
+               };
+               F9849FFF10B5DE8E009E9878 /* Release-assert */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALWAYS_SEARCH_USER_PATHS = NO;
+                               COPY_PHASE_STRIP = NO;
+                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
+                               GCC_MODEL_TUNING = G5;
+                               INSTALL_PATH = /usr/bin;
+                               OTHER_LDFLAGS = "-Wl,-exported_symbol,__mh_execute_header";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = dyldinfo;
+                               STRIP_INSTALLED_PRODUCT = YES;
+                               STRIP_STYLE = debugging;
+                               ZERO_LINK = NO;
+                       };
+                       name = "Release-assert";
+               };
+               F984A00010B5DE8E009E9878 /* Release-assert */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALWAYS_SEARCH_USER_PATHS = NO;
+                               COPY_PHASE_STRIP = NO;
+                               DEBUG_INFORMATION_FORMAT = dwarf;
+                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_SYMBOLS_PRIVATE_EXTERN = YES;
+                               INSTALL_PATH = /usr/local/lib;
+                               PREBINDING = NO;
+                               PRODUCT_NAME = prunetrie;
+                       };
+                       name = "Release-assert";
+               };
+               F984A00110B5DE8E009E9878 /* Release-assert */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = YES;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               PRODUCT_NAME = "unit-tests";
+                       };
+                       name = "Release-assert";
+               };
                F9A3DDCB0ED762B800C590B9 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                        buildConfigurations = (
                                F933D91C09291AC90083EAC8 /* Debug */,
                                F933D91D09291AC90083EAC8 /* Release */,
+                               F9849FFA10B5DE8E009E9878 /* Release-assert */,
                        );
                        defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
+                       defaultConfigurationName = "Release-assert";
                };
                F933D91F09291AC90083EAC8 /* Build configuration list for PBXNativeTarget "ObjectDump" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                                F933D92009291AC90083EAC8 /* Debug */,
                                F933D92109291AC90083EAC8 /* Release */,
+                               F9849FFD10B5DE8E009E9878 /* Release-assert */,
                        );
                        defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
+                       defaultConfigurationName = "Release-assert";
                };
                F933D92309291AC90083EAC8 /* Build configuration list for PBXProject "ld64" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                                F933D92409291AC90083EAC8 /* Debug */,
                                F933D92509291AC90083EAC8 /* Release */,
+                               F9849FF810B5DE8E009E9878 /* Release-assert */,
                        );
                        defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
+                       defaultConfigurationName = "Release-assert";
                };
                F96D536D094A2773008E9EE8 /* Build configuration list for PBXAggregateTarget "unit-tests" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                                F96D536E094A2773008E9EE8 /* Debug */,
                                F96D536F094A2773008E9EE8 /* Release */,
+                               F984A00110B5DE8E009E9878 /* Release-assert */,
                        );
                        defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
+                       defaultConfigurationName = "Release-assert";
                };
                F9A3DDCF0ED762C100C590B9 /* Build configuration list for PBXNativeTarget "libprunetrie" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                                F9A3DDCB0ED762B800C590B9 /* Debug */,
                                F9A3DDCC0ED762B800C590B9 /* Release */,
+                               F984A00010B5DE8E009E9878 /* Release-assert */,
                        );
                        defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
+                       defaultConfigurationName = "Release-assert";
                };
                F9B1A26C0A3A568700DA8FAB /* Build configuration list for PBXAggregateTarget "all" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                                F9B1A26D0A3A568700DA8FAB /* Debug */,
                                F9B1A26E0A3A568700DA8FAB /* Release */,
+                               F9849FF910B5DE8E009E9878 /* Release-assert */,
                        );
                        defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
+                       defaultConfigurationName = "Release-assert";
                };
                F9B670050DDA176100E6D0DA /* Build configuration list for PBXNativeTarget "unwinddump" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                                F9B670060DDA176100E6D0DA /* Debug */,
                                F9B670070DDA176100E6D0DA /* Release */,
+                               F9849FFC10B5DE8E009E9878 /* Release-assert */,
                        );
                        defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
+                       defaultConfigurationName = "Release-assert";
                };
                F9BA516D0ECE58DA00D1D62E /* Build configuration list for PBXNativeTarget "dyldinfo" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                                F9BA51630ECE58BF00D1D62E /* Debug */,
                                F9BA51640ECE58BF00D1D62E /* Release */,
+                               F9849FFF10B5DE8E009E9878 /* Release-assert */,
                        );
                        defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
+                       defaultConfigurationName = "Release-assert";
                };
                F9EA72CF097454D5008B4F1D /* Build configuration list for PBXNativeTarget "machocheck" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                                F9EA72D0097454D5008B4F1D /* Debug */,
                                F9EA72D1097454D5008B4F1D /* Release */,
+                               F9849FFE10B5DE8E009E9878 /* Release-assert */,
                        );
                        defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
+                       defaultConfigurationName = "Release-assert";
                };
                F9EC77F00A2F8616002A3E39 /* Build configuration list for PBXNativeTarget "rebase" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                                F9EC77F10A2F8616002A3E39 /* Debug */,
                                F9EC77F20A2F8616002A3E39 /* Release */,
+                               F9849FFB10B5DE8E009E9878 /* Release-assert */,
                        );
                        defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
+                       defaultConfigurationName = "Release-assert";
                };
 /* End XCConfigurationList section */
        };
index 1f7a6295e19b002bc3c34ed14805a5bc9c564708..8517e87797ee4dc5911123fce7017aadb9959a26 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
  *
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -118,6 +118,7 @@ class Pointer32
 {
 public:
        typedef uint32_t        uint_t;
+       typedef int32_t         sint_t;
        typedef _E                      E;
        
        static uint64_t getP(const uint_t& from)                                INLINE { return _E::get32(from); }
@@ -130,6 +131,7 @@ class Pointer64
 {
 public:
        typedef uint64_t        uint_t;
+       typedef int64_t         sint_t;
        typedef _E                      E;
        
        static uint64_t getP(const uint_t& from)                                INLINE { return _E::get64(from); }
index 50982a16b8ce8f8b1d586a4fed431feae13e95ab..a9a69a7a54a7205f8af748df52af1efc914fb14d 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
  *
- * Copyright (c) 2005-2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2005-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 
 
 // stuff that will eventually go away once newer cctools headers are widespread
+#ifndef LC_LOAD_UPWARD_DYLIB
+       #define LC_LOAD_UPWARD_DYLIB (0x23|LC_REQ_DYLD) /* load of dylib whose initializers run later */
+#endif
+
 #ifndef CPU_SUBTYPE_ARM_V5TEJ
        #define CPU_SUBTYPE_ARM_V5TEJ           ((cpu_subtype_t) 7)
 #endif
 
 #endif 
 
+#ifndef S_THREAD_LOCAL_REGULAR
+       #define S_THREAD_LOCAL_REGULAR                   0x11
+#endif
+
+#ifndef S_THREAD_LOCAL_ZEROFILL
+       #define S_THREAD_LOCAL_ZEROFILL                  0x12
+#endif
+
+#ifndef S_THREAD_LOCAL_VARIABLES
+       #define S_THREAD_LOCAL_VARIABLES                 0x13
+#endif
+
+#ifndef S_THREAD_LOCAL_VARIABLE_POINTERS
+       #define S_THREAD_LOCAL_VARIABLE_POINTERS         0x14
+#endif
+
+#ifndef S_THREAD_LOCAL_INIT_FUNCTION_POINTERS
+       #define S_THREAD_LOCAL_INIT_FUNCTION_POINTERS    0x15
+#endif
+
+#ifndef MH_HAS_TLV_DESCRIPTORS
+       #define MH_HAS_TLV_DESCRIPTORS 0x800000
+#endif
+
+#ifndef X86_64_RELOC_TLV
+       #define X86_64_RELOC_TLV    9
+#endif
+
+#define GENERIC_RLEOC_TLV  5
+
+#ifndef EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
+       #define EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER 0x10
+#endif
+
+#ifndef EXPORT_SYMBOL_FLAGS_REEXPORT
+       #define EXPORT_SYMBOL_FLAGS_REEXPORT 0x08
+#endif
+
+// type internal to linker
+#define BIND_TYPE_OVERRIDE_OF_WEAKDEF_IN_DYLIB 0
+
+#ifndef LC_VERSION_MIN_MACOSX
+       #define LC_VERSION_MIN_MACOSX   0x24
+       #define LC_VERSION_MIN_IPHONEOS         0x25
+
+       struct version_min_command {
+               uint32_t        cmd;            /* LC_VERSION_MIN_MACOSX or LC_VERSION_MIN_IPHONEOS  */
+               uint32_t        cmdsize;        /* sizeof(struct min_version_command) */
+               uint32_t        version;        /* X.Y.Z is encoded in nibbles xxxx.yy.zz */
+               uint32_t        reserved;       /* zero */
+       };
+#endif
+
+#ifndef N_SYMBOL_RESOLVER
+       #define N_SYMBOL_RESOLVER 0x100
+#endif
+
+#ifndef LC_FUNCTION_STARTS
+       #define LC_FUNCTION_STARTS      0x26
+#endif
+
+#ifndef MH_NO_HEAP_EXECUTION
+       #define MH_NO_HEAP_EXECUTION 0x1000000
+#endif
+
+#ifndef LC_DYLD_ENVIRONMENT
+       #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
+
 
 //
 // This abstraction layer makes every mach-o file look like a 64-bit mach-o file with native endianness
@@ -471,7 +548,7 @@ public:
        void                    set_cmdsize(uint32_t value)                             INLINE { E::set32(fields.cmdsize, value); }
 
        const uint8_t*  uuid() const                                                    INLINE { return fields.uuid; }
-       void                    set_uuid(uint8_t u[16])                                 INLINE { memcpy(&fields.uuid, u, 16); }
+       void                    set_uuid(const uint8_t u[16])                   INLINE { memcpy(&fields.uuid, u, 16); }
                        
        typedef typename P::E           E;
 private:
@@ -1159,6 +1236,29 @@ private:
 };
 
 
+//
+// mach-o version load command
+//
+template <typename P>
+class macho_version_min_command {
+public:
+       uint32_t                cmd() const                                                             INLINE { return E::get32(fields.cmd); }
+       void                    set_cmd(uint32_t value)                                 INLINE { E::set32(fields.cmd, value); }
+
+       uint32_t                cmdsize() const                                                 INLINE { return E::get32(fields.cmdsize); }
+       void                    set_cmdsize(uint32_t value)                             INLINE { E::set32(fields.cmdsize, value); }
+
+       uint32_t                version() const                                                 INLINE { return fields.version; }
+       void                    set_version(uint32_t value)                             INLINE { E::set32(fields.version, value); }
+
+       uint32_t                reserved() const                                                INLINE { return fields.reserved; }
+       void                    set_reserved(uint32_t value)                    INLINE { E::set32(fields.reserved, value); }
+
+       typedef typename P::E           E;
+private:
+       version_min_command     fields;
+};
+
 
 
 #endif // __MACH_O_FILE_ABSTRACTION__
index 43284c4480df1612459d2e8ee5c8d601ac026642..7b30cad0580d5f47bab60d8305875ef1c5f373d4 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
  *
- * Copyright (c) 2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2008-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #define __MACH_O_TRIE__
 
 #include <algorithm>
+#include <assert.h>
 
 #include "MachOFileAbstraction.hpp"
 
+
 namespace mach_o {
 namespace trie {
 
@@ -42,25 +44,28 @@ struct Edge
 
 struct Node
 {
-                                               Node(const char* s) : fCummulativeString(s), fAddress(0), fFlags(0), fOrdered(false), 
+                                               Node(const char* s) : fCummulativeString(s), fAddress(0), fFlags(0), 
+                                                                                       fOther(0), fImportedName(NULL), fOrdered(false), 
                                                                                        fHaveExportInfo(false), fTrieOffset(0) {}
                                                ~Node() { }
        const char*                     fCummulativeString;
        std::vector<Edge>       fChildren;
        uint64_t                        fAddress;
-       uint32_t                        fFlags;
+       uint64_t                        fFlags;
+       uint64_t                        fOther;
+       const char*                     fImportedName;
        bool                            fOrdered;
        bool                            fHaveExportInfo;
        uint32_t                        fTrieOffset;
        
-       void addSymbol(const char* fullStr, uint64_t address, uint32_t flags) {
+       void addSymbol(const char* fullStr, uint64_t address, uint64_t flags, uint64_t other, const char* importName) {
                const char* partialStr = &fullStr[strlen(fCummulativeString)];
                for (std::vector<Edge>::iterator it = fChildren.begin(); it != fChildren.end(); ++it) {
                        Edge& e = *it;
                        int subStringLen = strlen(e.fSubString);
                        if ( strncmp(e.fSubString, partialStr, subStringLen) == 0 ) {
                                // already have matching edge, go down that path
-                               e.fChild->addSymbol(fullStr, address, flags);
+                               e.fChild->addSymbol(fullStr, address, flags, other, importName);
                                return;
                        }
                        else {
@@ -81,18 +86,30 @@ struct Node
                                                abEdge.fChild = bNode;
                                                Edge bcEdge(bcEdgeStr, cNode);
                                                bNode->fChildren.push_back(bcEdge);
-                                               bNode->addSymbol(fullStr, address, flags);
+                                               bNode->addSymbol(fullStr, address, flags, other, importName);
                                                return;
                                        }
                                }
                        }
                }
+               if ( flags & EXPORT_SYMBOL_FLAGS_REEXPORT ) {
+                       assert(importName != NULL);
+                       assert(other != 0);
+               }
+               if ( flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER ) {
+                       assert(other != 0);
+               }
                // no commonality with any existing child, make a new edge that is this whole string
                Node* newNode = new Node(strdup(fullStr));
                Edge newEdge(strdup(partialStr), newNode);
                fChildren.push_back(newEdge);
                newNode->fAddress = address;
                newNode->fFlags = flags;
+               newNode->fOther = other;
+               if ( (flags & EXPORT_SYMBOL_FLAGS_REEXPORT) && (importName != NULL) && (strcmp(fullStr,importName) != 0) )
+                       newNode->fImportedName = importName;
+               else
+                       newNode->fImportedName = NULL;
                newNode->fHaveExportInfo = true;
        }
        
@@ -115,14 +132,26 @@ struct Node
        }
 
        // byte for terminal node size in bytes, or 0x00 if not terminal node
-       // teminal node (uleb128 flags, uleb128 addr)
+       // teminal node (uleb128 flags, uleb128 addr [uleb128 other])
        // byte for child node count
        //  each child: zero terminated substring, uleb128 node offset
        bool updateOffset(uint32_t& offset) {
-               uint32_t nodeSize = 1; // byte for length of export info
-               if ( fHaveExportInfo ) 
-                       nodeSize += uleb128_size(fFlags) + uleb128_size(fAddress);
-
+               uint32_t nodeSize = 1; // length of export info when no export info
+               if ( fHaveExportInfo ) {
+                       if ( fFlags & EXPORT_SYMBOL_FLAGS_REEXPORT ) {
+                               nodeSize = uleb128_size(fFlags) + uleb128_size(fOther); // ordinal
+                               if ( fImportedName != NULL )
+                                       nodeSize += strlen(fImportedName);
+                               ++nodeSize; // trailing zero in imported name
+                       }
+                       else {
+                               nodeSize = uleb128_size(fFlags) + uleb128_size(fAddress);
+                               if ( fFlags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER )
+                                       nodeSize += uleb128_size(fOther);
+                       }
+                       // do have export info, overall node size so far is uleb128 of export info + export info
+                       nodeSize += uleb128_size(nodeSize); 
+               }
                // add children
                ++nodeSize; // byte for count of chidren
                for (std::vector<Edge>::iterator it = fChildren.begin(); it != fChildren.end(); ++it) {
@@ -139,13 +168,42 @@ struct Node
 
        void appendToStream(std::vector<uint8_t>& out) {
                if ( fHaveExportInfo ) {
-                       // nodes with export info: size, flags, address
-                       out.push_back(uleb128_size(fFlags) + uleb128_size(fAddress));
-                       append_uleb128(fFlags, out);
-                       append_uleb128(fAddress, out);
+                       if ( fFlags & EXPORT_SYMBOL_FLAGS_REEXPORT ) {
+                               if ( fImportedName != NULL ) {
+                                       // nodes with re-export info: size, flags, ordinal, string
+                                       uint32_t nodeSize = uleb128_size(fFlags) + uleb128_size(fOther) + strlen(fImportedName) + 1;
+                                       out.push_back(nodeSize);
+                                       append_uleb128(fFlags, out);
+                                       append_uleb128(fOther, out);
+                                       append_string(fImportedName, out);
+                               }
+                               else {
+                                       // nodes with re-export info: size, flags, ordinal, empty-string
+                                       uint32_t nodeSize = uleb128_size(fFlags) + uleb128_size(fOther) + 1;
+                                       out.push_back(nodeSize);
+                                       append_uleb128(fFlags, out);
+                                       append_uleb128(fOther, out);
+                                       out.push_back(0);
+                               }
+                       }
+                       else if ( fFlags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER ) {
+                               // nodes with export info: size, flags, address, other
+                               uint32_t nodeSize = uleb128_size(fFlags) + uleb128_size(fAddress) + uleb128_size(fOther);
+                               out.push_back(nodeSize);
+                               append_uleb128(fFlags, out);
+                               append_uleb128(fAddress, out);
+                               append_uleb128(fOther, out);
+                       }
+                       else {
+                               // nodes with export info: size, flags, address
+                               uint32_t nodeSize = uleb128_size(fFlags) + uleb128_size(fAddress);
+                               out.push_back(nodeSize);
+                               append_uleb128(fFlags, out);
+                               append_uleb128(fAddress, out);
+                       }
                }
                else {
-                       // no export info
+                       // no export info uleb128 of zero is one byte of zero
                        out.push_back(0);
                }
                // write number of children
@@ -216,22 +274,25 @@ struct Entry
        const char*             name;
        uint64_t                address;
        uint64_t                flags;
+       uint64_t                other;
+       const char*             importName;
 };
 
 
-inline void makeTrie(const std::vector<Entry>& input, std::vector<uint8_t>& output)
+
+inline void makeTrie(const std::vector<Entry>& entries, std::vector<uint8_t>& output)
 {
        Node start(strdup(""));
        
        // make nodes for all exported symbols
-       for (std::vector<Entry>::const_iterator it = input.begin(); it != input.end(); ++it) {
-               start.addSymbol(it->name, it->address, it->flags);
+       for (std::vector<Entry>::const_iterator it = entries.begin(); it != entries.end(); ++it) {
+               start.addSymbol(it->name, it->address, it->flags, it->other, it->importName);
        }
 
        // create vector of nodes
        std::vector<Node*> orderedNodes;
-       orderedNodes.reserve(input.size()*2);
-       for (std::vector<Entry>::const_iterator it = input.begin(); it != input.end(); ++it) {
+       orderedNodes.reserve(entries.size()*2);
+       for (std::vector<Entry>::const_iterator it = entries.begin(); it != entries.end(); ++it) {
                start.addOrderedNodes(it->name, orderedNodes);
        }
        
@@ -263,18 +324,31 @@ struct EntryWithOffset
 
 
 static inline void processExportNode(const uint8_t* const start, const uint8_t* p, const uint8_t* const end, 
-                                                                                       char* cummulativeString, int curStrOffset, std::vector<EntryWithOffset>& output) 
+                                                                       char* cummulativeString, int curStrOffset, 
+                                                                       std::vector<EntryWithOffset>& output) 
 {
        if ( p >= end )
                throw "malformed trie, node past end";
-       const uint8_t terminalSize = *p++;
+       const uint8_t terminalSize = read_uleb128(p, end);
        const uint8_t* children = p + terminalSize;
        if ( terminalSize != 0 ) {
                EntryWithOffset e;
                e.nodeOffset = p-start;
                e.entry.name = strdup(cummulativeString);
                e.entry.flags = read_uleb128(p, end);
-               e.entry.address = read_uleb128(p, end); 
+               if ( e.entry.flags & EXPORT_SYMBOL_FLAGS_REEXPORT ) {
+                       e.entry.address = 0;
+                       e.entry.other = read_uleb128(p, end); // dylib ordinal
+                       e.entry.importName = (char*)p;
+               }
+               else {
+                       e.entry.address = read_uleb128(p, end); 
+                       if ( e.entry.flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER )
+                               e.entry.other = read_uleb128(p, end); 
+                       else
+                               e.entry.other = 0;
+                       e.entry.importName = NULL;
+               }
                output.push_back(e);
        }
        const uint8_t childrenCount = *children++;
@@ -293,8 +367,8 @@ static inline void processExportNode(const uint8_t* const start, const uint8_t*
 
 
 inline void parseTrie(const uint8_t* start, const uint8_t* end, std::vector<Entry>& output)
-{      
-       // empty tree has no entries
+{
+       // empty trie has no entries
        if ( start == end )
                return;
        char cummulativeString[4000];
index 2a449f14f20cd53d11d154fb8ad374d54bd71a63..11455505dd5c489b34cb4e1418cbad5878d6aa7c 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
  *
- * Copyright (c) 2005-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2005-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 struct ppc
 {
        typedef Pointer32<BigEndian>            P;
-       
-       enum ReferenceKinds {  kNoFixUp, kFollowOn, kGroupSubordinate, kPointer, kPointerWeakImport,   
-                                                       kPointerDiff16, kPointerDiff32, kPointerDiff=kPointerDiff32, kPointerDiff64,  
-                                                       kBranch24, kBranch24WeakImport, kBranch14,
-                                                       kPICBaseLow16, kPICBaseLow14, kPICBaseHigh16, 
-                                                       kAbsLow16, kAbsLow14, kAbsHigh16, kAbsHigh16AddLow, 
-                                                       kDtraceProbe, kDtraceProbeSite, kDtraceIsEnabledSite, kDtraceTypeReference };
 };
 
 struct ppc64
 {
        typedef Pointer64<BigEndian>            P;
-       
-       enum ReferenceKinds {  kNoFixUp, kFollowOn, kGroupSubordinate, kPointer, kPointerWeakImport, 
-                                                       kPointerDiff16, kPointerDiff32, kPointerDiff64, kPointerDiff=kPointerDiff64,
-                                                       kBranch24, kBranch24WeakImport, kBranch14,
-                                                       kPICBaseLow16, kPICBaseLow14, kPICBaseHigh16, 
-                                                       kAbsLow16, kAbsLow14, kAbsHigh16, kAbsHigh16AddLow, 
-                                                       kDtraceProbe, kDtraceProbeSite, kDtraceIsEnabledSite, kDtraceTypeReference  };
 };
 
 struct x86
 {
        typedef Pointer32<LittleEndian>         P;
-       
-       enum ReferenceKinds {  kNoFixUp, kFollowOn, kGroupSubordinate, kPointer, kPointerWeakImport, kPointerDiff, kPointerDiff32=kPointerDiff, kPointerDiff16,
-                                                       kPCRel32, kPCRel32WeakImport, kAbsolute32,  kPCRel16, kPCRel8, 
-                                                       kImageOffset32, kPointerDiff24, kSectionOffset24,
-                                                       kDtraceProbe, kDtraceProbeSite, kDtraceIsEnabledSite, kDtraceTypeReference  };
 };
 
 struct x86_64
 {
        typedef Pointer64<LittleEndian>         P;
-       
-       enum ReferenceKinds {  kNoFixUp, kFollowOn, kGroupSubordinate, kPointer, kPointer32, kPointerWeakImport, kPointerDiff, kPointerDiff32, 
-                                                       kPCRel32, kPCRel32_1, kPCRel32_2, kPCRel32_4,
-                                                       kBranchPCRel32, kBranchPCRel32WeakImport,
-                                                       kPCRel32GOTLoad, kPCRel32GOTLoadWeakImport,
-                                                       kPCRel32GOT, kPCRel32GOTWeakImport, kBranchPCRel8, kGOTNoFixUp, 
-                                                       kImageOffset32, kPointerDiff24, kSectionOffset24,
-                                                       kDtraceProbe, kDtraceProbeSite, kDtraceIsEnabledSite, kDtraceTypeReference  };
 };
 
 struct arm
 {
        typedef Pointer32<LittleEndian>         P;
-       
-       enum ReferenceKinds {  kNoFixUp, kFollowOn, kGroupSubordinate, kPointer, kPointerWeakImport, kPointerDiff, 
-                                                       kPointerDiff32=kPointerDiff, kReadOnlyPointer, kPointerDiff12, 
-                                                       kBranch24, kBranch24WeakImport, kThumbBranch22, kThumbBranch22WeakImport, 
-                                                       kDtraceProbe, kDtraceProbeSite, kDtraceIsEnabledSite, kDtraceTypeReference  };
 };
 
 #endif // __ARCHITECTURES__
diff --git a/src/ld/ArchiveReader.hpp b/src/ld/ArchiveReader.hpp
deleted file mode 100644 (file)
index b8f1a5c..0000000
+++ /dev/null
@@ -1,467 +0,0 @@
-/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
- *
- * Copyright (c) 2005-2008 Apple Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-#ifndef __OBJECT_FILE_ARCHIVE__
-#define __OBJECT_FILE_ARCHIVE__
-
-#include <stdint.h>
-#include <math.h>
-#include <unistd.h>
-#include <sys/param.h>
-#include <mach-o/ranlib.h>
-#include <ar.h>
-
-#include <vector>
-#include <set>
-#include <algorithm>
-#include <ext/hash_map>
-
-#include "MachOFileAbstraction.hpp"
-#include "ObjectFile.h"
-#include "MachOReaderRelocatable.hpp"
-#if LTO_SUPPORT
-       #include "LTOReader.hpp"
-#endif
-namespace archive {
-
-typedef const struct ranlib* ConstRanLibPtr;
-
-template <typename A>
-class Reader : public ObjectFile::Reader
-{
-public:
-       static bool                                                                             validFile(const uint8_t* fileContent, uint64_t fileLength);
-                                                                                                       Reader(const uint8_t fileContent[], uint64_t fileLength,
-                                                                                                                       const char* path, time_t modTime, 
-                                                                                                                       const LibraryOptions& archiveOptions, 
-                                                                                                                       const ObjectFile::ReaderOptions& options, uint32_t ordinalBase);
-       virtual                                                                                 ~Reader() {}
-
-       virtual const char*                                                             getPath()                       { return fPath; }
-       virtual time_t                                                                  getModificationTime(){ return fModTime; }
-       virtual DebugInfoKind                                                   getDebugInfoKind()      { return ObjectFile::Reader::kDebugInfoNone; }
-       virtual std::vector<class ObjectFile::Atom*>&   getAtoms();
-       virtual std::vector<class ObjectFile::Atom*>*   getJustInTimeAtomsFor(const char* name);
-       virtual std::vector<Stab>*                                              getStabs()                      { return NULL; }
-       virtual bool                                                                    optimize(const std::vector<ObjectFile::Atom*>&, std::vector<ObjectFile::Atom*>&, 
-                                                                                                                               std::vector<const char*>&, const std::set<ObjectFile::Atom*>&,
-                                                                                                                               std::vector<ObjectFile::Atom*>& newDeadAtoms,
-                                                                                                                               uint32_t, ObjectFile::Reader* writer, 
-                                                                                                                               ObjectFile::Atom* entryPointAtom,
-                                                                                                                               const std::vector<const char*>& llvmOptions,
-                                                                                                                               bool allGlobalsAReDeadStripRoots, int okind, 
-                                                                                                                               bool verbose, bool saveTemps, const char* outputFilePath,
-                                                                                                                               bool pie, bool allowTextRelocs);
-
-private:
-       static bool                                                                             validMachOFile(const uint8_t* fileContent, uint64_t fileLength);
-       static bool                                                                             validLTOFile(const uint8_t* fileContent, uint64_t fileLength);
-       static cpu_type_t                                                               architecture();
-
-
-       class Entry : ar_hdr
-       {
-       public:
-               const char*                     getName() const;
-               time_t                          getModTime() const;
-               const uint8_t*          getContent() const;
-               uint32_t                        getContentSize() const;
-               const Entry*            getNext() const;
-       private:
-               bool                            hasLongName() const;
-               unsigned int            getLongNameSpace() const;
-
-       };
-
-       class CStringEquals
-       {
-       public:
-               bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
-       };
-       typedef __gnu_cxx::hash_map<const char*, const struct ranlib*, __gnu_cxx::hash<const char*>, CStringEquals> NameToEntryMap;
-
-       typedef typename A::P                                                   P;
-       typedef typename A::P::E                                                E;
-
-       const struct ranlib*                                                    ranlibHashSearch(const char* name);
-       ObjectFile::Reader*                                                             makeObjectReaderForMember(const Entry* member);
-       void                                                                                    dumpTableOfContents();
-       void                                                                                    buildHashTable();
-
-       const char*                                                                             fPath;
-       time_t                                                                                  fModTime;
-       const ObjectFile::ReaderOptions&                                fOptions;
-       uint32_t                                                                                fOrdinalBase;
-       const uint8_t*                                                                  fFileContent;
-       uint64_t                                                                                fFileLength;
-       const struct ranlib*                                                    fTableOfContents;
-       uint32_t                                                                                fTableOfContentCount;
-       const char*                                                                             fStringPool;
-       std::vector<class ObjectFile::Atom*>                    fAllAtoms;
-       std::vector<class ObjectFile::Reader*>                  fInstantiatedReaders;
-       std::set<const class Entry*>                                    fInstantiatedEntries;
-       std::set<const class Entry*>                                    fPossibleEntries;
-       NameToEntryMap                                                                  fHashTable;
-       bool                                                                                    fForceLoad;
-
-       static std::vector<class ObjectFile::Atom*>             fgEmptyList;
-};
-
-template <typename A>
-std::vector<class ObjectFile::Atom*>           Reader<A>::fgEmptyList;
-
-
-template <typename A>
-bool Reader<A>::Entry::hasLongName() const
-{
-       return ( strncmp(this->ar_name, AR_EFMT1, strlen(AR_EFMT1)) == 0 );
-}
-
-template <typename A>
-unsigned int Reader<A>::Entry::getLongNameSpace() const
-{
-       char* endptr;
-       long result = strtol(&this->ar_name[strlen(AR_EFMT1)], &endptr, 10);
-       return result;
-}
-
-template <typename A>
-const char* Reader<A>::Entry::getName() 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;
-       }
-       else {
-               static char shortName[20];
-               strncpy(shortName, this->ar_name, 16);
-               shortName[16] = '\0';
-               char* space = strchr(shortName, ' ');
-               if ( space != NULL )
-                       *space = '\0';
-               return shortName;
-       }
-}
-
-template <typename A>
-time_t Reader<A>::Entry::getModTime() const
-{
-       char temp[14];
-       strncpy(temp, this->ar_date, 12);
-       temp[12] = '\0';
-       char* endptr;
-       return (time_t)strtol(temp, &endptr, 10);
-}
-
-
-template <typename A>
-const uint8_t* Reader<A>::Entry::getContent() const
-{
-       if ( this->hasLongName() )
-               return ((uint8_t*)this) + sizeof(ar_hdr) + this->getLongNameSpace();
-       else
-               return ((uint8_t*)this) + sizeof(ar_hdr);
-}
-
-
-template <typename A>
-uint32_t Reader<A>::Entry::getContentSize() const
-{
-       char temp[12];
-       strncpy(temp, this->ar_size, 10);
-       temp[10] = '\0';
-       char* endptr;
-       long size = strtol(temp, &endptr, 10);
-       // long name is included in ar_size
-       if ( this->hasLongName() )
-               size -= this->getLongNameSpace();
-       return size;
-}
-
-
-template <typename A>
-const class Reader<A>::Entry* Reader<A>::Entry::getNext() const
-{
-       const uint8_t* p = this->getContent() + getContentSize();
-       p = (const uint8_t*)(((uintptr_t)p+3) & (-4));  // 4-byte align
-       return (class Reader<A>::Entry*)p;
-}
-
-
-template <> cpu_type_t Reader<ppc>::architecture()    { return CPU_TYPE_POWERPC; }
-template <> cpu_type_t Reader<ppc64>::architecture()  { return CPU_TYPE_POWERPC64; }
-template <> cpu_type_t Reader<x86>::architecture()    { return CPU_TYPE_I386; }
-template <> cpu_type_t Reader<x86_64>::architecture() { return CPU_TYPE_X86_64; }
-template <> cpu_type_t Reader<arm>::architecture()    { return CPU_TYPE_ARM; }
-
-
-template <typename A>
-bool Reader<A>::validMachOFile(const uint8_t* fileContent, uint64_t fileLength)
-{
-       return mach_o::relocatable::Reader<A>::validFile(fileContent);
-}
-
-template <typename A>
-bool Reader<A>::validLTOFile(const uint8_t* fileContent, uint64_t fileLength)
-{
-#if LTO_SUPPORT
-       return lto::Reader::validFile(fileContent, fileLength, architecture());
-#else
-       return false;
-#endif
-}
-
-
-
-template <typename A>
-bool Reader<A>::validFile(const uint8_t* fileContent, uint64_t fileLength)
-{
-       // must have valid archive header
-       if ( strncmp((const char*)fileContent, "!<arch>\n", 8) != 0 )
-               return false;
-               
-       // peak at first .o file and verify it is correct architecture
-       const Entry* const start = (Entry*)&fileContent[8];
-       const Entry* const end = (Entry*)&fileContent[fileLength];
-       for (const Entry* p=start; p < end; p = p->getNext()) {
-               const char* memberName = p->getName();
-               // skip option table-of-content member
-               if ( (p==start) && ((strcmp(memberName, SYMDEF_SORTED) == 0) || (strcmp(memberName, SYMDEF) == 0)) )
-                       continue;
-               // archive is valid if first .o file is valid
-               return (validMachOFile(p->getContent(), p->getContentSize()) || validLTOFile(p->getContent(), p->getContentSize()));
-       }       
-       // empty archive
-       return true;
-}
-
-template <typename A>
-Reader<A>::Reader(const uint8_t fileContent[], uint64_t fileLength, const char* path, time_t modTime, 
-                                       const LibraryOptions& archiveOptions, 
-                                       const ObjectFile::ReaderOptions& options, uint32_t ordinalBase)
- : fPath(NULL), fModTime(modTime), fOptions(options), fOrdinalBase(ordinalBase), fFileContent(NULL), 
-       fTableOfContents(NULL), fTableOfContentCount(0), fStringPool(NULL), fForceLoad(archiveOptions.fForceLoad)
-{
-       fPath = strdup(path);
-       fFileContent = fileContent;
-       fFileLength = fileLength;
-
-       if ( strncmp((const char*)fileContent, "!<arch>\n", 8) != 0 )
-               throw "not an archive";
-
-       // write out path for -whatsloaded option
-       if ( options.fLogAllFiles )
-               printf("%s\n", path);
-
-       if ( !options.fFullyLoadArchives && !fForceLoad ) {
-               const Entry* const firstMember = (Entry*)&fFileContent[8];
-               if ( (strcmp(firstMember->getName(), SYMDEF_SORTED) == 0) || (strcmp(firstMember->getName(), SYMDEF) == 0) ) {
-                       const uint8_t* contents = firstMember->getContent();
-                       uint32_t ranlibArrayLen = E::get32(*((uint32_t*)contents));
-                       fTableOfContents = (const struct ranlib*)&contents[4];
-                       fTableOfContentCount = ranlibArrayLen / sizeof(struct ranlib);
-                       fStringPool = (const char*)&contents[ranlibArrayLen+8];
-                       if ( ((uint8_t*)(&fTableOfContents[fTableOfContentCount]) > &fileContent[fileLength])
-                               || ((uint8_t*)fStringPool > &fileContent[fileLength]) )
-                               throw "malformed archive, perhaps wrong architecture";
-                       this->buildHashTable();
-               }
-               else
-                       throw "archive has no table of contents";
-       }
-}
-
-
-template <typename A>
-ObjectFile::Reader* Reader<A>::makeObjectReaderForMember(const Entry* member)
-{
-       const char* memberName = member->getName();
-       char memberPath[strlen(fPath) + strlen(memberName)+4];
-       strcpy(memberPath, fPath);
-       strcat(memberPath, "(");
-       strcat(memberPath, memberName);
-       strcat(memberPath, ")");
-       //fprintf(stderr, "using %s from %s\n", memberName, fPath);
-       try {
-               // offset the ordinals in this mach-o .o file, so that atoms layout in same order as in archive
-               uint32_t ordinalBase =  fOrdinalBase + (uint8_t*)member - fFileContent;
-               if ( validMachOFile(member->getContent(), member->getContentSize()) ) {
-                       return new typename mach_o::relocatable::Reader<A>::Reader(member->getContent(), memberPath, member->getModTime(), fOptions, ordinalBase);
-               }
-#if LTO_SUPPORT
-               else if ( validLTOFile(member->getContent(), member->getContentSize()) ) {
-                       return new typename lto::Reader(member->getContent(), member->getContentSize(), memberPath, member->getModTime(), fOptions, architecture());
-               }
-#endif
-               throwf("archive member '%s' with length %d is not mach-o or bitcode", memberName, member->getContentSize());
-       }
-       catch (const char* msg) {
-               throwf("in %s, %s", memberPath, msg);
-       }
-}
-
-
-template <typename A>
-std::vector<class ObjectFile::Atom*>&  Reader<A>::getAtoms()
-{
-       if ( fOptions.fFullyLoadArchives || fForceLoad ) {
-               // build vector of all atoms from all .o files in this archive
-               const Entry* const start = (Entry*)&fFileContent[8];
-               const Entry* const end = (Entry*)&fFileContent[fFileLength];
-               for (const Entry* p=start; p < end; p = p->getNext()) {
-                       const char* memberName = p->getName();
-                       if ( (p==start) && ((strcmp(memberName, SYMDEF_SORTED) == 0) || (strcmp(memberName, SYMDEF) == 0)) )
-                               continue;
-                       if ( fOptions.fWhyLoad ) {
-                               if ( fForceLoad )
-                                       printf("-force_load forced load of %s(%s)\n", this->getPath(), memberName);
-                               else
-                                       printf("-all_load forced load of %s(%s)\n", this->getPath(), memberName);
-                       }
-                       ObjectFile::Reader* r = this->makeObjectReaderForMember(p);
-                       std::vector<class ObjectFile::Atom*>&   atoms = r->getAtoms();
-                       fAllAtoms.insert(fAllAtoms.end(), atoms.begin(), atoms.end());
-                       fInstantiatedReaders.push_back(r);
-               }
-               return fAllAtoms;
-       }
-       else if ( fOptions.fLoadAllObjcObjectsFromArchives ) {
-               // build vector of all atoms from all .o files containing objc classes in this archive
-               for(class NameToEntryMap::iterator it = fHashTable.begin(); it != fHashTable.end(); ++it) {
-                       if ( (strncmp(it->first, ".objc_c", 7) == 0) || (strncmp(it->first, "_OBJC_CLASS_$_", 14) == 0) ) {
-                               const Entry* member = (Entry*)&fFileContent[E::get32(it->second->ran_off)];
-                               if ( fInstantiatedEntries.count(member) == 0 ) {
-                                       if ( fOptions.fWhyLoad )
-                                               printf("-ObjC forced load of %s(%s)\n", this->getPath(), member->getName());
-                                       // only return these atoms once
-                                       fInstantiatedEntries.insert(member);
-                                       ObjectFile::Reader* r = makeObjectReaderForMember(member);
-                                       std::vector<class ObjectFile::Atom*>&   atoms = r->getAtoms();
-                                       fAllAtoms.insert(fAllAtoms.end(), atoms.begin(), atoms.end());
-                                       fInstantiatedReaders.push_back(r);
-                               }
-                       }
-               }
-               return fAllAtoms;
-       }
-       else {
-               // return nonthing for now, getJustInTimeAtomsFor() will return atoms as needed
-               return fgEmptyList;
-       }
-}
-
-template <typename A>
-bool  Reader<A>::optimize(const std::vector<ObjectFile::Atom*>& allAtoms, std::vector<ObjectFile::Atom*>& newAtoms, 
-                                                       std::vector<const char*>& additionalUndefines, const std::set<ObjectFile::Atom*>& deadAtoms,
-                                                       std::vector<ObjectFile::Atom*>& newDeadAtoms,
-                                                       uint32_t nextOrdinal, ObjectFile::Reader* writer, ObjectFile::Atom* entryPointAtom, 
-                                                       const std::vector<const char*>& llvmOptions,
-                                                       bool allGlobalsAReDeadStripRoots, int okind, 
-                                                       bool verbose, bool saveTemps, const char* outputFilePath,
-                                                       bool pie, bool allowTextRelocs)
-{
-       bool result = false;
-       for(std::vector<ObjectFile::Reader*>::iterator it=fInstantiatedReaders.begin(); it != fInstantiatedReaders.end(); ++it) {
-               result |= (*it)->optimize(allAtoms, newAtoms, additionalUndefines, deadAtoms, newDeadAtoms, nextOrdinal, 
-                                                       writer, entryPointAtom, llvmOptions, allGlobalsAReDeadStripRoots, okind, 
-                                                       verbose, saveTemps, outputFilePath, pie, allowTextRelocs);
-       }
-       return result;
-}
-
-
-
-template <typename A>
-ConstRanLibPtr  Reader<A>::ranlibHashSearch(const char* name)
-{
-       class NameToEntryMap::iterator pos = fHashTable.find(name);
-       if ( pos != fHashTable.end() )
-               return pos->second;
-       else
-               return NULL;
-}
-
-template <typename A>
-void Reader<A>::buildHashTable()
-{
-       // walk through list backwards, adding/overwriting entries
-       // this assures that with duplicates those earliest in the list will be found
-       for (int i = fTableOfContentCount-1; i >= 0; --i) {
-               const struct ranlib* entry = &fTableOfContents[i];
-               const char* entryName = &fStringPool[E::get32(entry->ran_un.ran_strx)];
-               const Entry* member = (Entry*)&fFileContent[E::get32(entry->ran_off)];
-               //fprintf(stderr, "adding hash %d, %s -> %p\n", i, entryName, entry);
-               fHashTable[entryName] = entry;
-               fPossibleEntries.insert(member);
-       }
-}
-
-template <typename A>
-void Reader<A>::dumpTableOfContents()
-{
-       for (unsigned int i=0; i < fTableOfContentCount; ++i) {
-               const struct ranlib* e = &fTableOfContents[i];
-               printf("%s in %s\n", &fStringPool[E::get32(e->ran_un.ran_strx)], ((Entry*)&fFileContent[E::get32(e->ran_off)])->getName());
-       }
-}
-
-template <typename A>
-std::vector<class ObjectFile::Atom*>* Reader<A>::getJustInTimeAtomsFor(const char* name)
-{
-       if ( fOptions.fFullyLoadArchives || fForceLoad ) {
-               return NULL;
-       }
-       else {
-               const struct ranlib* result = NULL;
-               // do a hash search of table of contents looking for requested symbol
-               result = ranlibHashSearch(name);
-               if ( result != NULL ) {
-                       const Entry* member = (Entry*)&fFileContent[E::get32(result->ran_off)];
-                       if ( fInstantiatedEntries.count(member) == 0 ) {
-                               if ( fOptions.fWhyLoad ) 
-                                       printf("%s forced load of %s(%s)\n", name, this->getPath(), member->getName());
-                               // only return these atoms once
-                               fInstantiatedEntries.insert(member);
-                               ObjectFile::Reader* r = makeObjectReaderForMember(member);
-                               fInstantiatedReaders.push_back(r);
-                               return new std::vector<class ObjectFile::Atom*>(r->getAtoms());
-                       }
-               }
-               //fprintf(stderr, "%s NOT found in archive %s\n", name, fPath);
-               return NULL;
-       }
-}
-
-
-
-
-
-}; // namespace archive
-
-
-#endif // __OBJECT_FILE_ARCHIVE__
diff --git a/src/ld/ExecutableFile.h b/src/ld/ExecutableFile.h
deleted file mode 100644 (file)
index dca22f7..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
- *
- * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-#ifndef __EXECUTABLEFILE__
-#define __EXECUTABLEFILE__
-
-#include <stdint.h>
-#include <vector>
-
-#include "ObjectFile.h"
-#include "Options.h"
-
-
-namespace ExecutableFile {
-
-       struct DyLibUsed
-       {
-               ObjectFile::Reader*             reader;
-               LibraryOptions                  options;
-       };
-
-       class Writer : public ObjectFile::Reader
-       {
-       public:
-               virtual                                         ~Writer() {};
-
-               virtual const char*                                                             getPath() = 0;
-               virtual std::vector<class ObjectFile::Atom*>&   getAtoms() = 0;
-               virtual std::vector<class ObjectFile::Atom*>*   getJustInTimeAtomsFor(const char* name) = 0;
-               virtual ObjectFile::Atom&                                               makeObjcInfoAtom(ObjectFile::Reader::ObjcConstraint objcContraint, 
-                                                                                                                                               bool objcReplacementClasses) = 0;
-               virtual class ObjectFile::Atom*                                 getUndefinedProxyAtom(const char* name) = 0;
-               virtual void                                                                    addSynthesizedAtoms(const std::vector<class ObjectFile::Atom*>& existingAtoms,
-                                                                                                                                                         class ObjectFile::Atom* dyldClassicHelperAtom,
-                                                                                                                                                         class ObjectFile::Atom* dyldCompressedHelperAtom,
-                                                                                                                                                         class ObjectFile::Atom* dyldLazyDylibHelperAtom,
-                                                                                                                                                         bool biggerThanTwoGigs,
-                                                                                                                                                         uint32_t dylibSymbolCount,
-                                                                                                                                                         std::vector<class ObjectFile::Atom*>& newAtoms) = 0;
-               virtual uint64_t                                                                write(std::vector<class ObjectFile::Atom*>& atoms,
-                                                                                                                         std::vector<class ObjectFile::Reader::Stab>& stabs,
-                                                                                                                         class ObjectFile::Atom* entryPointAtom,
-                                                                                                                         bool createUUID, bool canScatter,
-                                                                                                                         ObjectFile::Reader::CpuConstraint cpuConstraint,
-                                                                                                                         std::set<const class ObjectFile::Atom*>& atomsThatOverrideWeak,
-                                                                                                                         bool hasExternalWeakDefinitions) = 0;
-
-       protected:
-                                                                       Writer(std::vector<DyLibUsed>&) {};
-       };
-
-};
-
-#endif // __EXECUTABLEFILE__
diff --git a/src/ld/HeaderAndLoadCommands.hpp b/src/ld/HeaderAndLoadCommands.hpp
new file mode 100644 (file)
index 0000000..2c97dba
--- /dev/null
@@ -0,0 +1,1391 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __HEADER_LOAD_COMMANDS_HPP__
+#define __HEADER_LOAD_COMMANDS_HPP__
+
+#include <stdlib.h>
+#include <limits.h>
+#include <unistd.h>
+#include <mach-o/loader.h>
+
+#include <vector>
+
+#include "MachOFileAbstraction.hpp"
+#include "Options.h"
+#include "ld.hpp"
+
+namespace ld {
+namespace tool {
+
+class HeaderAndLoadCommandsAbtract : public ld::Atom
+{
+public:
+                                                       HeaderAndLoadCommandsAbtract(const ld::Section& sect, ld::Atom::Definition d, 
+                                                                                               ld::Atom::Combine c, ld::Atom::Scope s, ld::Atom::ContentType ct, 
+                                                                                               ld::Atom::SymbolTableInclusion i, bool dds, bool thumb, bool al, 
+                                                                                               ld::Atom::Alignment a) : ld::Atom(sect, d, c, s, ct, i, dds, thumb, al, a) { }
+
+       virtual void setUUID(const uint8_t digest[16]) = 0;
+       virtual void recopyUUIDCommand() = 0;
+};
+
+template <typename A>
+class HeaderAndLoadCommandsAtom : public HeaderAndLoadCommandsAbtract
+{
+public:
+                                                                                               HeaderAndLoadCommandsAtom(const Options& opts, ld::Internal& state, 
+                                                                                                                                                       OutputFile& writer);
+
+       // overrides of ld::Atom
+       virtual ld::File*                                                       file() const            { return NULL; }
+       virtual bool                                                            translationUnitSource(const char** dir, const char** nm) const
+                                                                                                                                       { return false; }
+       virtual const char*                                                     name() const            { return "mach-o header and load commands"; }
+       virtual uint64_t                                                        size() const;
+       virtual uint64_t                                                        objectAddress() const { return _address; }
+       virtual void                                                            copyRawContent(uint8_t buffer[]) const;
+
+       // overrides of HeaderAndLoadCommandsAbtract
+       virtual void setUUID(const uint8_t digest[16])  { memcpy(_uuid, digest, 16); }
+       virtual void recopyUUIDCommand();
+       
+private:
+       typedef typename A::P                                           P;
+       typedef typename A::P::E                                        E;
+       typedef typename A::P::uint_t                           pint_t;
+       
+       unsigned int                            nonHiddenSectionCount() const;
+       unsigned int                            segmentCount() const;
+       static uint32_t                         alignedSize(uint32_t x);
+       uint32_t                                        magic() const;
+       uint32_t                                        cpuType() const;
+       uint32_t                                        cpuSubType() const;
+       uint32_t                                        flags() const;
+       uint32_t                                        fileType() const;
+       uint32_t                                        commandsCount() const;
+       uint32_t                                        threadLoadCommandSize() const;
+       uint8_t*                                        copySingleSegmentLoadCommand(uint8_t* p) const;
+       uint8_t*                                        copySegmentLoadCommands(uint8_t* p) const;
+       uint8_t*                                        copyDyldInfoLoadCommand(uint8_t* p) const;
+       uint8_t*                                        copySymbolTableLoadCommand(uint8_t* p) const;
+       uint8_t*                                        copyDynamicSymbolTableLoadCommand(uint8_t* p) const;
+       uint8_t*                                        copyDyldLoadCommand(uint8_t* p) const;
+       uint8_t*                                        copyDylibIDLoadCommand(uint8_t* p) const;
+       uint8_t*                                        copyRoutinesLoadCommand(uint8_t* p) const;
+       uint8_t*                                        copyUUIDLoadCommand(uint8_t* p) const;
+       uint8_t*                                        copyVersionLoadCommand(uint8_t* p) const;
+       uint8_t*                                        copyThreadsLoadCommand(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;
+       uint8_t*                                        copyRPathLoadCommand(uint8_t* p, const char*) const;
+       uint8_t*                                        copySubFrameworkLoadCommand(uint8_t* p) const;
+       uint8_t*                                        copyAllowableClientLoadCommand(uint8_t* p, const char* client) const;
+       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*                                        copyDyldEnvLoadCommand(uint8_t* p, const char* env) const;
+       
+       uint32_t                                        sectionFlags(ld::Internal::FinalSection* sect) const;
+       bool                                            sectionTakesNoDiskSpace(ld::Internal::FinalSection* sect) const;
+       
+
+       const Options&                          _options;
+       ld::Internal&                           _state;
+       OutputFile&                                     _writer;
+       pint_t                                          _address;
+       bool                                            _hasDyldInfoLoadCommand;
+       bool                                            _hasDyldLoadCommand;
+       bool                                            _hasDylibIDLoadCommand;
+       bool                                            _hasThreadLoadCommand;
+       bool                                            _hasEncryptionLoadCommand;
+       bool                                            _hasSplitSegInfoLoadCommand;
+       bool                                            _hasRoutinesLoadCommand;
+       bool                                            _hasUUIDLoadCommand;
+       bool                                            _hasSymbolTableLoadCommand;
+       bool                                            _hasDynamicSymbolTableLoadCommand;
+       bool                                            _hasRPathLoadCommands;
+       bool                                            _hasSubFrameworkLoadCommand;
+       bool                                            _hasVersionLoadCommand;
+       bool                                            _hasFunctionStartsLoadCommand;
+       uint32_t                                        _dylibLoadCommmandsCount;
+       uint32_t                                        _allowableClientLoadCommmandsCount;
+       uint32_t                                        _dyldEnvironExrasCount;
+       std::vector<const char*>        _subLibraryNames;
+       std::vector<const char*>        _subUmbrellaNames;
+       uint8_t                                         _uuid[16];
+       mutable macho_uuid_command<P>*  _uuidCmdInOutputBuffer;
+       
+       static ld::Section                      _s_section;
+       static ld::Section                      _s_preload_section;
+};
+
+template <typename A>
+ld::Section HeaderAndLoadCommandsAtom<A>::_s_section("__TEXT", "__mach_header", ld::Section::typeMachHeader, true);
+template <typename A>
+ld::Section HeaderAndLoadCommandsAtom<A>::_s_preload_section("__HEADER", "__mach_header", ld::Section::typeMachHeader, true);
+
+
+template <typename A>
+HeaderAndLoadCommandsAtom<A>::HeaderAndLoadCommandsAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+       : HeaderAndLoadCommandsAbtract((opts.outputKind() == Options::kPreload) ? _s_preload_section : _s_section, 
+                               ld::Atom::definitionRegular, ld::Atom::combineNever, 
+                               ld::Atom::scopeTranslationUnit, ld::Atom::typeUnclassified, 
+                               ld::Atom::symbolTableNotIn, false, false, false, 
+                               (opts.outputKind() == Options::kPreload) ? ld::Atom::Alignment(0) : ld::Atom::Alignment(12) ), 
+               _options(opts), _state(state), _writer(writer), _address(0), _uuidCmdInOutputBuffer(NULL)
+{
+       bzero(_uuid, 16);
+       _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);
+       _hasEncryptionLoadCommand = opts.makeEncryptable();
+       _hasSplitSegInfoLoadCommand = opts.sharedRegionEligible();
+       _hasRoutinesLoadCommand = (opts.initFunctionName() != NULL);
+       _hasSymbolTableLoadCommand = true;
+       _hasUUIDLoadCommand = (opts.UUIDMode() != Options::kUUIDNone);
+       switch ( opts.outputKind() ) {
+               case Options::kDynamicExecutable:
+               case Options::kDynamicLibrary:
+               case Options::kDynamicBundle:
+               case Options::kDyld:
+               case Options::kKextBundle:
+                       _hasDynamicSymbolTableLoadCommand = true;
+                       break;
+               case Options::kObjectFile:
+                       if ( ! state.someObjectFileHasDwarf )
+                               _hasUUIDLoadCommand = false;
+                       _hasDynamicSymbolTableLoadCommand = false;
+                       for (std::vector<ld::Internal::FinalSection*>::iterator it = _state.sections.begin(); it != _state.sections.end(); ++it) {
+                               if ( (*it)->type() == ld::Section::typeNonLazyPointer ) {
+                                       _hasDynamicSymbolTableLoadCommand = true;
+                                       break;
+                               }
+                       }
+                       break;
+               case Options::kStaticExecutable:
+                       _hasDynamicSymbolTableLoadCommand = false;
+                       break;
+               case Options::kPreload:
+                       _hasDynamicSymbolTableLoadCommand = opts.positionIndependentExecutable();
+                       break;
+       }
+       _hasRPathLoadCommands = (_options.rpaths().size() != 0);
+       _hasSubFrameworkLoadCommand = (_options.umbrellaName() != NULL);
+       _hasVersionLoadCommand = _options.addVersionLoadCommand();
+       _hasFunctionStartsLoadCommand = _options.addFunctionStarts();
+       _dylibLoadCommmandsCount = _writer.dylibCount();
+       _allowableClientLoadCommmandsCount = _options.allowableClients().size();
+       _dyldEnvironExrasCount = _options.dyldEnvironExtras().size();
+       if ( ! _options.useSimplifiedDylibReExports() ) {
+               // target OS does not support LC_REEXPORT_DYLIB, so use old complicated load commands
+               for(uint32_t ord=1; ord <= _writer.dylibCount(); ++ord) {
+                       const ld::dylib::File* dylib = _writer.dylibByOrdinal(ord);
+                       if ( dylib->willBeReExported() ) {
+                               // if child says it is an sub-framework of the image being created, then nothing to do here
+                               bool isSubFramework = false;
+                               const char* childInUmbrella = dylib->parentUmbrella();
+                               if ( childInUmbrella != NULL ) {
+                                       const char* myLeaf = strrchr(_options.installPath(), '/');
+                                       if ( myLeaf != NULL ) {
+                                               if ( strcmp(childInUmbrella, &myLeaf[1]) == 0 )
+                                                       isSubFramework = true;
+                                       }
+                               }
+                               // LC_SUB_FRAMEWORK is in child, so do nothing in parent 
+                               if ( ! isSubFramework ) {
+                                       // this dylib also needs a sub_x load command
+                                       bool isFrameworkReExport = false;
+                                       const char* lastSlash = strrchr(dylib->installPath(), '/');
+                                       if ( lastSlash != NULL ) {
+                                               char frameworkName[strlen(lastSlash)+20];
+                                               sprintf(frameworkName, "/%s.framework/", &lastSlash[1]);
+                                               isFrameworkReExport = (strstr(dylib->installPath(), frameworkName) != NULL);
+                                       }
+                                       if ( isFrameworkReExport ) {
+                                               // needs a LC_SUB_UMBRELLA command
+                                               _subUmbrellaNames.push_back(&lastSlash[1]);
+                                       }
+                                       else {
+                                               // needs a LC_SUB_LIBRARY command
+                                               const char* nameStart = &lastSlash[1];
+                                               if ( lastSlash == NULL )
+                                                       nameStart = dylib->installPath();
+                                               int len = strlen(nameStart);
+                                               const char* dot = strchr(nameStart, '.');
+                                               if ( dot != NULL )
+                                                       len = dot - nameStart;
+                                               char* subLibName = new char[len+1];
+                                               strlcpy(subLibName, nameStart, len+1);
+                                               _subLibraryNames.push_back(subLibName);
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+template <typename A>
+uint32_t HeaderAndLoadCommandsAtom<A>::alignedSize(uint32_t size)
+{
+       if ( sizeof(pint_t) == 4 )
+               return ((size+3) & (-4));       // 4-byte align all load commands for 32-bit mach-o
+       else
+               return ((size+7) & (-8));       // 8-byte align all load commands for 64-bit mach-o
+}
+
+
+template <typename A>
+unsigned int HeaderAndLoadCommandsAtom<A>::nonHiddenSectionCount() const
+{
+       unsigned int count = 0;
+       for (std::vector<ld::Internal::FinalSection*>::iterator it = _state.sections.begin(); it != _state.sections.end(); ++it) {
+               if ( ! (*it)->isSectionHidden() && ((*it)->type() != ld::Section::typeTentativeDefs) )
+                       ++count;
+       }
+       return count;
+}
+
+template <typename A>
+unsigned int HeaderAndLoadCommandsAtom<A>::segmentCount() const
+{
+       if ( _options.outputKind() == Options::kObjectFile ) {
+               // .o files have one anonymous segment that contains all sections
+               return 1;
+       }
+       
+       unsigned int count = 0;
+       const char* lastSegName = "";
+       for (std::vector<ld::Internal::FinalSection*>::iterator it = _state.sections.begin(); it != _state.sections.end(); ++it) {
+               if ( _options.outputKind() == Options::kPreload ) {
+                       if ( (*it)->type() == ld::Section::typeMachHeader )
+                               continue; // for -preload, don't put hidden __HEADER segment into output
+                       if ( (*it)->type() == ld::Section::typeLinkEdit )
+                               continue; // for -preload, don't put hidden __LINKEDIT segment into output
+               }
+               if ( strcmp(lastSegName, (*it)->segmentName()) != 0 ) {
+                       lastSegName = (*it)->segmentName();
+                       ++count;
+               }
+       }
+       return count;
+}
+
+
+template <typename A>
+uint64_t HeaderAndLoadCommandsAtom<A>::size() const
+{
+       uint32_t sz = sizeof(macho_header<P>);
+       
+       sz += sizeof(macho_segment_command<P>) * this->segmentCount();
+       sz += sizeof(macho_section<P>) * this->nonHiddenSectionCount();
+
+       if ( _hasDylibIDLoadCommand )
+               sz += alignedSize(sizeof(macho_dylib_command<P>) + strlen(_options.installPath()) + 1);
+               
+       if ( _hasDyldInfoLoadCommand )
+               sz += sizeof(macho_dyld_info_command<P>);
+       
+       if ( _hasSymbolTableLoadCommand )
+               sz += sizeof(macho_symtab_command<P>);
+               
+       if ( _hasDynamicSymbolTableLoadCommand )
+               sz += sizeof(macho_dysymtab_command<P>);
+       
+       if ( _hasDyldLoadCommand )
+               sz += alignedSize(sizeof(macho_dylinker_command<P>) + strlen(_options.dyldInstallPath()) + 1);
+
+       if ( _hasRoutinesLoadCommand ) 
+               sz += sizeof(macho_routines_command<P>);
+               
+       if ( _hasUUIDLoadCommand )
+               sz += sizeof(macho_uuid_command<P>);
+
+       if ( _hasVersionLoadCommand )
+               sz += sizeof(macho_version_min_command<P>);
+               
+       if ( _hasThreadLoadCommand )
+               sz += this->threadLoadCommandSize();
+               
+       if ( _hasEncryptionLoadCommand )
+               sz += sizeof(macho_encryption_info_command<P>);
+
+       if ( _hasSplitSegInfoLoadCommand )
+               sz += sizeof(macho_linkedit_data_command<P>);
+       
+       for(uint32_t ord=1; ord <= _writer.dylibCount(); ++ord) {
+               sz += alignedSize(sizeof(macho_dylib_command<P>) + strlen(_writer.dylibByOrdinal(ord)->installPath()) + 1);
+       }
+       
+       if ( _hasRPathLoadCommands ) {
+               const std::vector<const char*>& rpaths = _options.rpaths();
+               for (std::vector<const char*>::const_iterator it = rpaths.begin(); it != rpaths.end(); ++it) {
+                       sz += alignedSize(sizeof(macho_rpath_command<P>) + strlen(*it) + 1);
+               }
+       }
+       
+       if ( _hasSubFrameworkLoadCommand )
+               sz += alignedSize(sizeof(macho_sub_framework_command<P>) + strlen(_options.umbrellaName()) + 1);
+       
+       for (std::vector<const char*>::const_iterator it = _subLibraryNames.begin(); it != _subLibraryNames.end(); ++it) {
+               sz += alignedSize(sizeof(macho_sub_library_command<P>) + strlen(*it) + 1);
+       }
+
+       for (std::vector<const char*>::const_iterator it = _subUmbrellaNames.begin(); it != _subUmbrellaNames.end(); ++it) {
+               sz += alignedSize(sizeof(macho_sub_umbrella_command<P>) + strlen(*it) + 1);
+       }
+
+       if ( _allowableClientLoadCommmandsCount != 0 ) {
+               const std::vector<const char*>& clients = _options.allowableClients();
+               for (std::vector<const char*>::const_iterator it = clients.begin(); it != clients.end(); ++it) {
+                       sz += alignedSize(sizeof(macho_sub_client_command<P>) + strlen(*it) + 1);
+               }
+       }
+       
+       if ( _dyldEnvironExrasCount != 0 ) {
+               const std::vector<const char*>& extras = _options.dyldEnvironExtras();
+               for (std::vector<const char*>::const_iterator it = extras.begin(); it != extras.end(); ++it) {
+                       sz += alignedSize(sizeof(macho_dylinker_command<P>) + strlen(*it) + 1);
+               }
+       }
+
+       if ( _hasFunctionStartsLoadCommand )
+               sz += sizeof(macho_linkedit_data_command<P>);
+
+       return sz;
+}
+
+template <typename A>
+uint32_t HeaderAndLoadCommandsAtom<A>::commandsCount() const
+{
+       uint32_t count = this->segmentCount();
+       
+       if ( _hasDylibIDLoadCommand )
+               ++count;
+               
+       if ( _hasDyldInfoLoadCommand )
+               ++count;
+       
+       if ( _hasSymbolTableLoadCommand )
+               ++count;
+               
+       if ( _hasDynamicSymbolTableLoadCommand )
+               ++count;
+       
+       if ( _hasDyldLoadCommand )
+               ++count;
+               
+       if ( _hasRoutinesLoadCommand ) 
+               ++count;
+               
+       if ( _hasUUIDLoadCommand )
+               ++count;
+       
+       if ( _hasVersionLoadCommand )
+               ++count;
+
+       if ( _hasThreadLoadCommand )
+               ++count;
+               
+       if ( _hasEncryptionLoadCommand )
+               ++count;
+       
+       if ( _hasSplitSegInfoLoadCommand )
+               ++count;
+       
+       count += _dylibLoadCommmandsCount;
+
+       count += _options.rpaths().size();
+       
+       if ( _hasSubFrameworkLoadCommand )
+               ++count;
+       
+       count += _subLibraryNames.size();
+       
+       count += _subUmbrellaNames.size();
+
+       count += _allowableClientLoadCommmandsCount;
+       
+       count += _dyldEnvironExrasCount;
+       
+       if ( _hasFunctionStartsLoadCommand )
+               ++count;
+
+       return count;
+}
+
+template <typename A>
+uint32_t HeaderAndLoadCommandsAtom<A>::fileType() const
+{
+       switch ( _options.outputKind() ) {
+               case Options::kDynamicExecutable:
+               case Options::kStaticExecutable:
+                       return MH_EXECUTE;
+               case Options::kDynamicLibrary:
+                       return MH_DYLIB;
+               case Options::kDynamicBundle:
+                       return MH_BUNDLE;
+               case Options::kObjectFile:
+                       return MH_OBJECT;
+               case Options::kDyld:
+                       return MH_DYLINKER;
+               case Options::kPreload:
+                       return MH_PRELOAD;
+               case Options::kKextBundle:
+                       return MH_KEXT_BUNDLE;
+       }
+       throw "unknonwn mach-o file type";
+}
+
+template <typename A>
+uint32_t HeaderAndLoadCommandsAtom<A>::flags() const
+{
+       uint32_t bits = 0;
+       if ( _options.outputKind() == Options::kObjectFile ) {
+               if ( _state.allObjectFilesScatterable )
+                       bits = MH_SUBSECTIONS_VIA_SYMBOLS;
+       }
+       else {
+               if ( _options.outputKind() == Options::kStaticExecutable ) {
+                       bits |= MH_NOUNDEFS;
+               }
+               else if ( _options.outputKind() == Options::kPreload ) {
+                       bits |= MH_NOUNDEFS;
+                       if ( _options.positionIndependentExecutable() ) 
+                               bits |= MH_PIE;
+               }
+               else {
+                       bits = MH_DYLDLINK;
+                       switch ( _options.nameSpace() ) {
+                               case Options::kTwoLevelNameSpace:
+                                       bits |= MH_TWOLEVEL | MH_NOUNDEFS;
+                                       break;
+                               case Options::kFlatNameSpace:
+                                       break;
+                               case Options::kForceFlatNameSpace:
+                                       bits |= MH_FORCE_FLAT;
+                                       break;
+                       }
+                       if ( _writer.hasWeakExternalSymbols || _writer.overridesWeakExternalSymbols )
+                               bits |= MH_WEAK_DEFINES;
+                       if ( _writer.usesWeakExternalSymbols || _writer.hasWeakExternalSymbols )
+                               bits |= MH_BINDS_TO_WEAK;
+                       if ( _options.prebind() )
+                               bits |= MH_PREBOUND;
+                       if ( _options.splitSeg() )
+                               bits |= MH_SPLIT_SEGS;
+                       if ( (_options.outputKind() == Options::kDynamicLibrary) 
+                                       && _writer._noReExportedDylibs 
+                                       && _options.useSimplifiedDylibReExports() ) {
+                               bits |= MH_NO_REEXPORTED_DYLIBS;
+                       }
+                       if ( _options.positionIndependentExecutable() && ! _writer.pieDisabled ) 
+                               bits |= MH_PIE;
+                       if ( _options.markAutoDeadStripDylib() ) 
+                               bits |= MH_DEAD_STRIPPABLE_DYLIB;
+                       if ( _writer.hasThreadLocalVariableDefinitions )
+                               bits |= MH_HAS_TLV_DESCRIPTORS;
+                       if ( _options.hasNonExecutableHeap() )
+                               bits |= MH_NO_HEAP_EXECUTION;
+               }
+               if ( _options.hasExecutableStack() )
+                       bits |= MH_ALLOW_STACK_EXECUTION;
+       }
+       return bits;
+}
+
+template <> uint32_t HeaderAndLoadCommandsAtom<ppc>::magic() const             { return MH_MAGIC; }
+template <> uint32_t HeaderAndLoadCommandsAtom<ppc64>::magic() const           { return MH_MAGIC_64; }
+template <> uint32_t HeaderAndLoadCommandsAtom<x86>::magic() const             { return MH_MAGIC; }
+template <> uint32_t HeaderAndLoadCommandsAtom<x86_64>::magic() const  { return MH_MAGIC_64; }
+template <> uint32_t HeaderAndLoadCommandsAtom<arm>::magic() const             { return MH_MAGIC; }
+
+template <> uint32_t HeaderAndLoadCommandsAtom<ppc>::cpuType() const   { return CPU_TYPE_POWERPC; }
+template <> uint32_t HeaderAndLoadCommandsAtom<ppc64>::cpuType() const { return CPU_TYPE_POWERPC64; }
+template <> uint32_t HeaderAndLoadCommandsAtom<x86>::cpuType() const   { return CPU_TYPE_I386; }
+template <> uint32_t HeaderAndLoadCommandsAtom<x86_64>::cpuType() const        { return CPU_TYPE_X86_64; }
+template <> uint32_t HeaderAndLoadCommandsAtom<arm>::cpuType() const   { return CPU_TYPE_ARM; }
+
+
+template <>
+uint32_t HeaderAndLoadCommandsAtom<ppc>::cpuSubType() const
+{
+       return _state.cpuSubType;
+}
+
+template <>
+uint32_t HeaderAndLoadCommandsAtom<ppc64>::cpuSubType() const
+{
+       if ( (_options.outputKind() == Options::kDynamicExecutable) && (_options.macosxVersionMin() >= ld::mac10_5) )
+               return (CPU_SUBTYPE_POWERPC_ALL | 0x80000000);
+       else
+               return CPU_SUBTYPE_POWERPC_ALL;
+}
+
+template <>
+uint32_t HeaderAndLoadCommandsAtom<x86>::cpuSubType() const
+{
+       return CPU_SUBTYPE_I386_ALL;
+}
+
+template <>
+uint32_t HeaderAndLoadCommandsAtom<x86_64>::cpuSubType() const
+{
+       if ( (_options.outputKind() == Options::kDynamicExecutable) && (_options.macosxVersionMin() >= ld::mac10_5) )
+               return (CPU_SUBTYPE_X86_64_ALL | 0x80000000);
+       else
+               return CPU_SUBTYPE_X86_64_ALL;
+}
+
+template <>
+uint32_t HeaderAndLoadCommandsAtom<arm>::cpuSubType() const
+{
+       return _state.cpuSubType;
+}
+
+
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copySingleSegmentLoadCommand(uint8_t* p) const
+{
+       // in .o files there is just one segment load command with a blank name
+       // and all sections under it
+       macho_segment_command<P>* cmd = (macho_segment_command<P>*)p;
+       cmd->set_cmd(macho_segment_command<P>::CMD);
+       cmd->set_segname("");
+       cmd->set_vmaddr(_options.baseAddress());        
+       cmd->set_vmsize(0);             // updated after sections set
+       cmd->set_fileoff(0);    // updated after sections set
+       cmd->set_filesize(0);   // updated after sections set
+       cmd->set_maxprot(VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE);
+       cmd->set_initprot(VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE);
+       cmd->set_nsects(this->nonHiddenSectionCount());
+       cmd->set_flags(0);
+       // add sections array
+       macho_section<P>* msect = (macho_section<P>*)&p[sizeof(macho_segment_command<P>)];
+       for (std::vector<ld::Internal::FinalSection*>::iterator sit = _state.sections.begin(); sit != _state.sections.end(); ++sit)  {
+               ld::Internal::FinalSection* fsect = *sit;
+               if ( fsect->isSectionHidden() ) 
+                       continue;
+               if ( fsect->type() == ld::Section::typeTentativeDefs ) 
+                       continue;
+               msect->set_sectname(fsect->sectionName());
+               msect->set_segname(fsect->segmentName());
+               msect->set_addr(fsect->address);
+               msect->set_size(fsect->size);
+               msect->set_offset(fsect->fileOffset);
+               msect->set_align(fsect->alignment);
+               msect->set_reloff((fsect->relocCount == 0) ? 0 : _writer.sectionRelocationsSection->fileOffset + fsect->relocStart * sizeof(macho_relocation_info<P>));
+               msect->set_nreloc(fsect->relocCount);
+               msect->set_flags(sectionFlags(fsect));
+               msect->set_reserved1(fsect->indirectSymTabStartIndex);  
+               msect->set_reserved2(fsect->indirectSymTabElementSize); 
+               // update segment info
+               if ( cmd->fileoff() == 0 )
+                       cmd->set_fileoff(fsect->fileOffset);
+               cmd->set_vmsize(fsect->address + fsect->size - cmd->vmaddr());
+               if ( (fsect->type() != ld::Section::typeZeroFill) && (fsect->type() != ld::Section::typeTentativeDefs) )
+                       cmd->set_filesize(fsect->fileOffset + fsect->size - cmd->fileoff());
+               ++msect;
+       }
+       cmd->set_cmdsize(sizeof(macho_segment_command<P>) + cmd->nsects()*sizeof(macho_section<P>));
+       return p + cmd->cmdsize();
+}
+
+struct SegInfo {
+                                                                                               SegInfo(const char* n, const Options&);
+       const char*                                                                     segName;
+       uint32_t                                                                        nonHiddenSectionCount;
+       uint32_t                                                                        maxProt;
+       uint32_t                                                                        initProt;
+       std::vector<ld::Internal::FinalSection*>        sections;
+};
+
+
+SegInfo::SegInfo(const char* n, const Options& opts) 
+       : segName(n), nonHiddenSectionCount(0), maxProt(opts.maxSegProtection(n)), initProt(opts.initialSegProtection(n)) 
+{ 
+}
+
+
+template <typename A>
+uint32_t HeaderAndLoadCommandsAtom<A>::sectionFlags(ld::Internal::FinalSection* sect) const
+{
+       uint32_t bits;
+       switch ( sect->type() ) {
+               case ld::Section::typeUnclassified:
+                       if ( strcmp(sect->segmentName(), "__OBJC") == 0 )
+                               return S_REGULAR | S_ATTR_NO_DEAD_STRIP;
+                       else if ( (strcmp(sect->sectionName(), "__objc_classlist") == 0) && (strcmp(sect->segmentName(), "__DATA") == 0) )
+                               return S_REGULAR | S_ATTR_NO_DEAD_STRIP;
+                       else if ( (strcmp(sect->sectionName(), "__objc_catlist") == 0) && (strcmp(sect->segmentName(), "__DATA") == 0) )
+                               return S_REGULAR | S_ATTR_NO_DEAD_STRIP;
+                       else if ( (strncmp(sect->sectionName(), "__objc_superrefs", 16) == 0) && (strcmp(sect->segmentName(), "__DATA") == 0) )
+                               return S_REGULAR | S_ATTR_NO_DEAD_STRIP;
+                       else
+                               return S_REGULAR;
+               case ld::Section::typeCode:
+                       bits = S_REGULAR | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS;
+                       if ( sect->hasLocalRelocs && ! _writer.pieDisabled )
+                               bits |= S_ATTR_LOC_RELOC;
+                       if ( sect->hasExternalRelocs )
+                               bits |= S_ATTR_EXT_RELOC;
+                       return bits;
+               case ld::Section::typePageZero:
+                       return S_REGULAR;
+               case ld::Section::typeImportProxies:
+                       return S_REGULAR;
+               case ld::Section::typeLinkEdit:
+                       return S_REGULAR;
+               case ld::Section::typeMachHeader:
+                       return S_REGULAR;
+               case ld::Section::typeStack:
+                       return S_REGULAR;
+               case ld::Section::typeLiteral4:
+                       return S_4BYTE_LITERALS;
+               case ld::Section::typeLiteral8:
+                       return S_8BYTE_LITERALS;
+               case ld::Section::typeLiteral16:
+                       return S_16BYTE_LITERALS;
+               case ld::Section::typeConstants:
+                       return S_REGULAR;
+               case ld::Section::typeTempLTO:
+                       assert(0 && "typeTempLTO should not make it to final linked image");
+                       return S_REGULAR;
+               case ld::Section::typeAbsoluteSymbols:
+                       assert(0 && "typeAbsoluteSymbols should not make it to final linked image");
+                       return S_REGULAR;
+               case ld::Section::typeCString:
+               case ld::Section::typeNonStdCString:
+                       return S_CSTRING_LITERALS;
+               case ld::Section::typeCStringPointer:
+                       return S_LITERAL_POINTERS | S_ATTR_NO_DEAD_STRIP;
+               case ld::Section::typeUTF16Strings:
+                       return S_REGULAR;
+               case ld::Section::typeCFString:
+                       return S_REGULAR;
+               case ld::Section::typeObjC1Classes:
+                       return S_REGULAR | S_ATTR_NO_DEAD_STRIP;
+               case ld::Section::typeCFI:
+                       return S_REGULAR;
+               case ld::Section::typeLSDA:
+                       return S_REGULAR;
+               case ld::Section::typeDtraceDOF:
+                       return S_DTRACE_DOF;
+               case ld::Section::typeUnwindInfo:
+                       return S_REGULAR;
+               case ld::Section::typeObjCClassRefs:
+               case ld::Section::typeObjC2CategoryList:
+                       return S_REGULAR | S_ATTR_NO_DEAD_STRIP;
+               case ld::Section::typeZeroFill:
+                       if ( _options.optimizeZeroFill() )
+                               return S_ZEROFILL;
+                       else
+                               return S_REGULAR;
+               case ld::Section::typeTentativeDefs:
+                       assert(0 && "typeTentativeDefs should not make it to final linked image");
+                       return S_REGULAR;
+               case ld::Section::typeLazyPointer:
+               case ld::Section::typeLazyPointerClose:
+                       return S_LAZY_SYMBOL_POINTERS;
+               case ld::Section::typeStubClose:
+               case ld::Section::typeStub:
+                       if ( sect->hasLocalRelocs )
+                               return S_SYMBOL_STUBS | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS | S_ATTR_LOC_RELOC;
+                       else
+                               return S_SYMBOL_STUBS | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS;
+               case ld::Section::typeNonLazyPointer:
+                       return S_NON_LAZY_SYMBOL_POINTERS;
+               case ld::Section::typeDyldInfo:
+                       return S_REGULAR;
+               case ld::Section::typeLazyDylibPointer:
+                       return S_LAZY_DYLIB_SYMBOL_POINTERS;
+               case ld::Section::typeStubHelper:
+                       if ( sect->hasLocalRelocs )
+                               return S_REGULAR | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS | S_ATTR_LOC_RELOC;
+                       else
+                               return S_REGULAR | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS;
+               case ld::Section::typeInitializerPointers:
+                       return S_MOD_INIT_FUNC_POINTERS;
+               case ld::Section::typeTerminatorPointers:
+                       return S_MOD_TERM_FUNC_POINTERS;
+               case ld::Section::typeTLVInitialValues:
+                       return S_THREAD_LOCAL_REGULAR;
+               case ld::Section::typeTLVZeroFill:
+                       return S_THREAD_LOCAL_ZEROFILL;
+               case ld::Section::typeTLVDefs:
+                       return S_THREAD_LOCAL_VARIABLES;
+               case ld::Section::typeTLVInitializerPointers:
+                       return S_THREAD_LOCAL_INIT_FUNCTION_POINTERS;
+               case ld::Section::typeTLVPointers:
+                       return S_THREAD_LOCAL_VARIABLE_POINTERS;
+               case ld::Section::typeFirstSection:
+                       assert(0 && "typeFirstSection should not make it to final linked image");
+                       return S_REGULAR;
+               case ld::Section::typeLastSection:
+                       assert(0 && "typeLastSection should not make it to final linked image");
+                       return S_REGULAR;
+       }
+       return S_REGULAR;
+}
+
+
+template <typename A>
+bool HeaderAndLoadCommandsAtom<A>::sectionTakesNoDiskSpace(ld::Internal::FinalSection* sect) const
+{
+       switch ( sect->type() ) {
+               case ld::Section::typeZeroFill:
+               case ld::Section::typeTLVZeroFill:
+                       return _options.optimizeZeroFill();
+               case ld::Section::typeAbsoluteSymbols:
+               case ld::Section::typeTentativeDefs:
+               case ld::Section::typeLastSection:
+                       return true;
+               default:
+                       break;
+       }
+       return false;
+}
+
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copySegmentLoadCommands(uint8_t* p) const
+{
+       // group sections into segments
+       std::vector<SegInfo> segs;
+       const char* lastSegName = "";
+       for (std::vector<ld::Internal::FinalSection*>::iterator it = _state.sections.begin(); it != _state.sections.end(); ++it) {
+               ld::Internal::FinalSection* sect = *it;
+               if ( _options.outputKind() == Options::kPreload ) {
+                       if ( (*it)->type() == ld::Section::typeMachHeader )
+                               continue; // for -preload, don't put hidden __HEADER segment into output
+                       if ( (*it)->type() == ld::Section::typeLinkEdit )
+                               continue; // for -preload, don't put hidden __LINKEDIT segment into output
+               }
+               if ( strcmp(lastSegName, sect->segmentName()) != 0 ) {
+                       SegInfo si(sect->segmentName(), _options);
+                       segs.push_back(si);
+                       lastSegName = sect->segmentName();
+               }
+               if ( ! sect->isSectionHidden() ) 
+                       segs.back().nonHiddenSectionCount++;
+               segs.back().sections.push_back(sect);
+       }
+       // write out segment load commands for each section with trailing sections
+       for (std::vector<SegInfo>::iterator it = segs.begin(); it != segs.end(); ++it) {
+               SegInfo& si = *it;
+               ld::Internal::FinalSection* lastNonZeroFillSection = NULL;
+               for (int i=si.sections.size()-1; i >= 0; --i) {
+                       if ( !sectionTakesNoDiskSpace(si.sections[i]) ) {
+                               lastNonZeroFillSection = si.sections[i];
+                               break;
+                       }
+               }
+               uint64_t vmsize = si.sections.back()->address + si.sections.back()->size - si.sections.front()->address;
+               vmsize = ((vmsize+_options.segmentAlignment()-1) & (-_options.segmentAlignment()));
+               uint64_t filesize = 0;
+               if ( lastNonZeroFillSection != NULL ) {
+                       filesize = lastNonZeroFillSection->address + lastNonZeroFillSection->size - si.sections.front()->address;
+                       // round up all segments to page aligned, except __LINKEDIT
+                       if ( (si.sections[0]->type() != ld::Section::typeLinkEdit) && (si.sections[0]->type() != ld::Section::typeImportProxies) )
+                               filesize = (filesize + _options.segmentAlignment()-1) & (-_options.segmentAlignment());
+               }
+               if ( si.sections.front()->type() == ld::Section::typePageZero )
+                       filesize = 0;
+               else if ( si.sections.front()->type() == ld::Section::typeStack )
+                       filesize = 0;
+               macho_segment_command<P>* segCmd = (macho_segment_command<P>*)p;
+               segCmd->set_cmd(macho_segment_command<P>::CMD);
+               segCmd->set_cmdsize(sizeof(macho_segment_command<P>) + si.nonHiddenSectionCount*sizeof(macho_section<P>));
+               segCmd->set_segname(si.sections.front()->segmentName());
+               segCmd->set_vmaddr(si.sections.front()->address);               
+               segCmd->set_vmsize(vmsize);     
+               segCmd->set_fileoff(si.sections.front()->fileOffset);
+               segCmd->set_filesize(filesize); 
+               segCmd->set_maxprot(si.maxProt);
+               segCmd->set_initprot(si.initProt);
+               segCmd->set_nsects(si.nonHiddenSectionCount);
+               segCmd->set_flags(0);
+               p += sizeof(macho_segment_command<P>);
+               macho_section<P>* msect = (macho_section<P>*)p;
+               for (std::vector<ld::Internal::FinalSection*>::iterator sit = si.sections.begin(); sit != si.sections.end(); ++sit) {
+                       ld::Internal::FinalSection* fsect = *sit;
+                       if ( ! fsect->isSectionHidden() ) {
+                               msect->set_sectname(fsect->sectionName());
+                               msect->set_segname(fsect->segmentName());
+                               msect->set_addr(fsect->address);
+                               msect->set_size(fsect->size);
+                               msect->set_offset(sectionTakesNoDiskSpace(fsect) ? 0 : fsect->fileOffset);
+                               msect->set_align(fsect->alignment);
+                               msect->set_reloff(0);           
+                               msect->set_nreloc(0);
+                               msect->set_flags(sectionFlags(fsect));
+                               msect->set_reserved1(fsect->indirectSymTabStartIndex);  
+                               msect->set_reserved2(fsect->indirectSymTabElementSize); 
+                               p += sizeof(macho_section<P>);
+                               ++msect;
+                       }
+               }
+       }
+
+       return p;
+}
+
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copySymbolTableLoadCommand(uint8_t* p) const
+{
+       // build LC_SYMTAB command
+       macho_symtab_command<P>*   symbolTableCmd = (macho_symtab_command<P>*)p;
+       symbolTableCmd->set_cmd(LC_SYMTAB);
+       symbolTableCmd->set_cmdsize(sizeof(macho_symtab_command<P>));
+       symbolTableCmd->set_nsyms(_writer.symbolTableSection->size/sizeof(macho_nlist<P>));
+       symbolTableCmd->set_symoff(_writer.symbolTableSection->size == 0 ? 0 : _writer.symbolTableSection->fileOffset);
+       symbolTableCmd->set_stroff(_writer.stringPoolSection->size == 0 ? 0 : _writer.stringPoolSection->fileOffset );
+       symbolTableCmd->set_strsize(_writer.stringPoolSection->size);
+       return p + sizeof(macho_symtab_command<P>);
+}
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyDynamicSymbolTableLoadCommand(uint8_t* p) const
+{
+       // build LC_SYMTAB command
+       macho_dysymtab_command<P>*   dynamicSymbolTableCmd = (macho_dysymtab_command<P>*)p;
+       dynamicSymbolTableCmd->set_cmd(LC_DYSYMTAB);
+       dynamicSymbolTableCmd->set_cmdsize(sizeof(macho_dysymtab_command<P>));
+       dynamicSymbolTableCmd->set_ilocalsym(0);
+       dynamicSymbolTableCmd->set_nlocalsym(_writer._localSymbolsCount);
+       dynamicSymbolTableCmd->set_iextdefsym(dynamicSymbolTableCmd->ilocalsym()+dynamicSymbolTableCmd->nlocalsym());
+       dynamicSymbolTableCmd->set_nextdefsym(_writer._globalSymbolsCount);
+       dynamicSymbolTableCmd->set_iundefsym(dynamicSymbolTableCmd->iextdefsym()+dynamicSymbolTableCmd->nextdefsym());
+       dynamicSymbolTableCmd->set_nundefsym(_writer._importSymbolsCount);
+
+       // FIX ME: support for 10.3 dylibs which need modules
+       //if ( fWriter.fModuleInfoAtom != NULL ) {
+       //      dynamicSymbolTableCmd->set_tocoff(fWriter.fModuleInfoAtom->getTableOfContentsFileOffset());
+       //      dynamicSymbolTableCmd->set_ntoc(fWriter.fSymbolTableExportCount);
+       //      dynamicSymbolTableCmd->set_modtaboff(fWriter.fModuleInfoAtom->getModuleTableFileOffset());
+       //      dynamicSymbolTableCmd->set_nmodtab(1);
+       //      dynamicSymbolTableCmd->set_extrefsymoff(fWriter.fModuleInfoAtom->getReferencesFileOffset());
+       //      dynamicSymbolTableCmd->set_nextrefsyms(fWriter.fModuleInfoAtom->getReferencesCount());
+       //}
+
+       bool hasIndirectSymbols = ( (_writer.indirectSymbolTableSection != NULL) && (_writer.indirectSymbolTableSection->size != 0) );
+       dynamicSymbolTableCmd->set_indirectsymoff(hasIndirectSymbols ? _writer.indirectSymbolTableSection->fileOffset : 0);
+       dynamicSymbolTableCmd->set_nindirectsyms( hasIndirectSymbols ? _writer.indirectSymbolTableSection->size/sizeof(uint32_t) : 0);
+
+       // FIX ME: support for classic relocations
+       if ( _options.outputKind() != Options::kObjectFile ) {
+               bool hasExternalRelocs = ( (_writer.externalRelocationsSection != NULL) && (_writer.externalRelocationsSection->size != 0) );
+               dynamicSymbolTableCmd->set_extreloff(hasExternalRelocs ? _writer.externalRelocationsSection->fileOffset : 0);
+               dynamicSymbolTableCmd->set_nextrel(  hasExternalRelocs ? _writer.externalRelocationsSection->size/8 : 0);
+               bool hasLocalRelocs = ( (_writer.localRelocationsSection != NULL) && (_writer.localRelocationsSection->size != 0) );
+               dynamicSymbolTableCmd->set_locreloff(hasLocalRelocs ? _writer.localRelocationsSection->fileOffset : 0);
+               dynamicSymbolTableCmd->set_nlocrel  (hasLocalRelocs ? _writer.localRelocationsSection->size/8 : 0);
+       }
+       return p + sizeof(macho_dysymtab_command<P>);
+}
+
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyDyldInfoLoadCommand(uint8_t* p) const
+{
+       // build LC_DYLD_INFO command
+       macho_dyld_info_command<P>*  cmd = (macho_dyld_info_command<P>*)p;
+       
+       cmd->set_cmd(LC_DYLD_INFO_ONLY);
+       cmd->set_cmdsize(sizeof(macho_dyld_info_command<P>));
+       if ( _writer.rebaseSection->size != 0 ) {
+               cmd->set_rebase_off(_writer.rebaseSection->fileOffset);
+               cmd->set_rebase_size(_writer.rebaseSection->size);
+       }
+       if ( _writer.bindingSection->size != 0 ) {
+               cmd->set_bind_off(_writer.bindingSection->fileOffset);
+               cmd->set_bind_size(_writer.bindingSection->size);
+       }
+       if ( _writer.weakBindingSection->size != 0 ) {
+               cmd->set_weak_bind_off(_writer.weakBindingSection->fileOffset);
+               cmd->set_weak_bind_size(_writer.weakBindingSection->size);
+       }
+       if ( _writer.lazyBindingSection->size != 0 ) {
+               cmd->set_lazy_bind_off(_writer.lazyBindingSection->fileOffset);
+               cmd->set_lazy_bind_size(_writer.lazyBindingSection->size);
+       }
+       if ( _writer.exportSection->size != 0 ) {
+               cmd->set_export_off(_writer.exportSection->fileOffset);
+               cmd->set_export_size(_writer.exportSection->size);
+       }
+       return p + sizeof(macho_dyld_info_command<P>);
+}
+
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyDyldLoadCommand(uint8_t* p) const
+{
+       uint32_t sz = alignedSize(sizeof(macho_dylinker_command<P>) + strlen(_options.dyldInstallPath()) + 1);
+       macho_dylinker_command<P>* cmd = (macho_dylinker_command<P>*)p;
+       if ( _options.outputKind() == Options::kDyld )
+               cmd->set_cmd(LC_ID_DYLINKER);
+       else
+               cmd->set_cmd(LC_LOAD_DYLINKER);
+       cmd->set_cmdsize(sz);
+       cmd->set_name_offset();
+       strcpy((char*)&p[sizeof(macho_dylinker_command<P>)], _options.dyldInstallPath());
+       return p + sz;
+}
+
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyDylibIDLoadCommand(uint8_t* p) const
+{
+       uint32_t sz = alignedSize(sizeof(macho_dylib_command<P>) + strlen(_options.installPath()) + 1);
+       macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)p;
+       cmd->set_cmd(LC_ID_DYLIB);
+       cmd->set_cmdsize(sz);
+       cmd->set_name_offset();
+       cmd->set_timestamp(1);  // needs to be some constant value that is different than DylibLoadCommandsAtom uses
+       cmd->set_current_version(_options.currentVersion());
+       cmd->set_compatibility_version(_options.compatibilityVersion());
+       strcpy((char*)&p[sizeof(macho_dylib_command<P>)], _options.installPath());
+       return p + sz;
+}
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyRoutinesLoadCommand(uint8_t* p) const
+{
+       pint_t initAddr = _state.entryPoint->finalAddress(); 
+       if ( _state.entryPoint->isThumb() )
+               initAddr |= 1ULL;
+       macho_routines_command<P>* cmd = (macho_routines_command<P>*)p;
+       cmd->set_cmd(macho_routines_command<P>::CMD);
+       cmd->set_cmdsize(sizeof(macho_routines_command<P>));
+       cmd->set_init_address(initAddr);
+       return p + sizeof(macho_routines_command<P>);
+}
+
+
+template <typename A>
+void HeaderAndLoadCommandsAtom<A>::recopyUUIDCommand() 
+{
+       assert(_uuidCmdInOutputBuffer != NULL);
+       _uuidCmdInOutputBuffer->set_uuid(_uuid);
+}
+
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyUUIDLoadCommand(uint8_t* p) const
+{
+       macho_uuid_command<P>* cmd = (macho_uuid_command<P>*)p;
+       cmd->set_cmd(LC_UUID);
+       cmd->set_cmdsize(sizeof(macho_uuid_command<P>));
+       cmd->set_uuid(_uuid);
+       _uuidCmdInOutputBuffer = cmd;    // save for later re-write by recopyUUIDCommand()
+       return p + sizeof(macho_uuid_command<P>);
+}
+
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyVersionLoadCommand(uint8_t* p) const
+{
+       macho_version_min_command<P>* cmd = (macho_version_min_command<P>*)p;
+       ld::MacVersionMin    macVersion      = _options.macosxVersionMin();
+       ld::IPhoneVersionMin iphoneOSVersion = _options.iphoneOSVersionMin();
+       assert( (macVersion != ld::macVersionUnset) || (iphoneOSVersion != ld::iPhoneVersionUnset) );
+       if ( macVersion != ld::macVersionUnset ) {
+               cmd->set_cmd(LC_VERSION_MIN_MACOSX);
+               cmd->set_cmdsize(sizeof(macho_version_min_command<P>));
+               cmd->set_version((uint32_t)macVersion);
+               cmd->set_reserved(0);
+       }
+       else {
+               cmd->set_cmd(LC_VERSION_MIN_IPHONEOS);
+               cmd->set_cmdsize(sizeof(macho_version_min_command<P>));
+               cmd->set_version((uint32_t)iphoneOSVersion);
+               cmd->set_reserved(0);
+       }
+       return p + sizeof(macho_version_min_command<P>);
+}
+
+
+template <>
+uint32_t HeaderAndLoadCommandsAtom<ppc>::threadLoadCommandSize() const
+{
+       return this->alignedSize(16 + 40*4);    // base size + PPC_THREAD_STATE_COUNT * 4
+}
+
+
+template <>
+uint8_t* HeaderAndLoadCommandsAtom<ppc>::copyThreadsLoadCommand(uint8_t* p) const
+{
+       assert(_state.entryPoint != NULL);
+       pint_t start = _state.entryPoint->finalAddress(); 
+       macho_thread_command<ppc::P>* cmd = (macho_thread_command<ppc::P>*)p;
+       cmd->set_cmd(LC_UNIXTHREAD);
+       cmd->set_cmdsize(threadLoadCommandSize());
+       cmd->set_flavor(1);                             // PPC_THREAD_STATE
+       cmd->set_count(40);                             // PPC_THREAD_STATE_COUNT;
+       cmd->set_thread_register(0, start);
+       if ( _options.hasCustomStack() )
+               cmd->set_thread_register(3, _options.customStackAddr());        // r1
+       return p + threadLoadCommandSize();
+}
+
+template <>
+uint32_t HeaderAndLoadCommandsAtom<ppc64>::threadLoadCommandSize() const
+{
+       return this->alignedSize(16 + 76*4);    // base size + PPC_THREAD_STATE64_COUNT * 4
+}
+
+template <>
+uint8_t* HeaderAndLoadCommandsAtom<ppc64>::copyThreadsLoadCommand(uint8_t* p) const
+{
+       assert(_state.entryPoint != NULL);
+       pint_t start = _state.entryPoint->finalAddress(); 
+       macho_thread_command<ppc::P>* cmd = (macho_thread_command<ppc::P>*)p;
+       cmd->set_cmd(LC_UNIXTHREAD);
+       cmd->set_cmdsize(threadLoadCommandSize());
+       cmd->set_flavor(5);                             // PPC_THREAD_STATE64
+       cmd->set_count(76);                             // PPC_THREAD_STATE64_COUNT;
+       cmd->set_thread_register(0, start);
+       if ( _options.hasCustomStack() )
+               cmd->set_thread_register(3, _options.customStackAddr());        // r1
+       return p + threadLoadCommandSize();
+}
+
+template <>
+uint32_t HeaderAndLoadCommandsAtom<x86>::threadLoadCommandSize() const
+{
+       return this->alignedSize(16 + 16*4);    // base size + i386_THREAD_STATE_COUNT * 4
+}
+
+template <>
+uint8_t* HeaderAndLoadCommandsAtom<x86>::copyThreadsLoadCommand(uint8_t* p) const
+{
+       assert(_state.entryPoint != NULL);
+       pint_t start = _state.entryPoint->finalAddress(); 
+       macho_thread_command<P>* cmd = (macho_thread_command<P>*)p;
+       cmd->set_cmd(LC_UNIXTHREAD);
+       cmd->set_cmdsize(threadLoadCommandSize());
+       cmd->set_flavor(1);                             // i386_THREAD_STATE
+       cmd->set_count(16);                             // i386_THREAD_STATE_COUNT;
+       cmd->set_thread_register(10, start);
+       if ( _options.hasCustomStack() )
+               cmd->set_thread_register(7, _options.customStackAddr());        // r1
+       return p + threadLoadCommandSize();
+}
+
+template <>
+uint32_t HeaderAndLoadCommandsAtom<x86_64>::threadLoadCommandSize() const
+{
+       return this->alignedSize(16 + x86_THREAD_STATE64_COUNT * 4); 
+}
+
+template <>
+uint8_t* HeaderAndLoadCommandsAtom<x86_64>::copyThreadsLoadCommand(uint8_t* p) const
+{
+       assert(_state.entryPoint != NULL);
+       pint_t start = _state.entryPoint->finalAddress(); 
+       macho_thread_command<P>* cmd = (macho_thread_command<P>*)p;
+       cmd->set_cmd(LC_UNIXTHREAD);
+       cmd->set_cmdsize(threadLoadCommandSize());
+       cmd->set_flavor(x86_THREAD_STATE64);                    
+       cmd->set_count(x86_THREAD_STATE64_COUNT);       
+       cmd->set_thread_register(16, start);            // rip 
+       if ( _options.hasCustomStack() )
+               cmd->set_thread_register(7, _options.customStackAddr());        // r1
+       return p + threadLoadCommandSize();
+}
+
+template <>
+uint32_t HeaderAndLoadCommandsAtom<arm>::threadLoadCommandSize() const
+{
+       return this->alignedSize(16 + 17 * 4); // base size + ARM_THREAD_STATE_COUNT * 4
+}
+
+template <>
+uint8_t* HeaderAndLoadCommandsAtom<arm>::copyThreadsLoadCommand(uint8_t* p) const
+{
+       assert(_state.entryPoint != NULL);
+       pint_t start = _state.entryPoint->finalAddress(); 
+       if ( _state.entryPoint->isThumb() )
+               start |= 1ULL;
+       macho_thread_command<P>* cmd = (macho_thread_command<P>*)p;
+       cmd->set_cmd(LC_UNIXTHREAD);
+       cmd->set_cmdsize(threadLoadCommandSize());
+       cmd->set_flavor(1);                     
+       cmd->set_count(17);     
+       cmd->set_thread_register(15, start);            // pc
+       if ( _options.hasCustomStack() )
+               cmd->set_thread_register(13, _options.customStackAddr());       // sp
+       return p + threadLoadCommandSize();
+}
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyEncryptionLoadCommand(uint8_t* p) const
+{
+       macho_encryption_info_command<P>* cmd = (macho_encryption_info_command<P>*)p;
+       cmd->set_cmd(LC_ENCRYPTION_INFO);
+       cmd->set_cmdsize(sizeof(macho_encryption_info_command<P>));
+       assert(_writer.encryptedTextStartOffset() != 0);
+       assert(_writer.encryptedTextEndOffset() != 0);
+       cmd->set_cryptoff(_writer.encryptedTextStartOffset());
+       cmd->set_cryptsize(_writer.encryptedTextEndOffset()-_writer.encryptedTextStartOffset());
+       cmd->set_cryptid(0);
+       return p + sizeof(macho_encryption_info_command<P>);
+}
+
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copySplitSegInfoLoadCommand(uint8_t* p) const
+{
+       macho_linkedit_data_command<P>* cmd = (macho_linkedit_data_command<P>*)p;
+       cmd->set_cmd(LC_SEGMENT_SPLIT_INFO);
+       cmd->set_cmdsize(sizeof(macho_linkedit_data_command<P>));
+       cmd->set_dataoff(_writer.splitSegInfoSection->fileOffset);
+       cmd->set_datasize(_writer.splitSegInfoSection->size);
+       return p + sizeof(macho_linkedit_data_command<P>);
+}
+
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyDylibLoadCommand(uint8_t* p, const ld::dylib::File* dylib) const
+{
+       uint32_t sz = alignedSize(sizeof(macho_dylib_command<P>) + strlen(dylib->installPath()) + 1);
+       macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)p;
+       // <rdar://problem/5529626> If only weak_import symbols are used, linker should use LD_LOAD_WEAK_DYLIB
+       bool autoWeakLoadDylib = false; // FIX
+                                                       //( (fWriter.fDylibReadersWithWeakImports.count(fInfo.reader) > 0) 
+                                                       //&& (fWriter.fDylibReadersWithNonWeakImports.count(fInfo.reader) == 0) );
+       if ( dylib->willBeLazyLoadedDylib() )
+               cmd->set_cmd(LC_LAZY_LOAD_DYLIB);
+       else if ( dylib->willBeWeakLinked() || autoWeakLoadDylib )
+               cmd->set_cmd(LC_LOAD_WEAK_DYLIB);
+       else if ( dylib->willBeReExported() && _options.useSimplifiedDylibReExports() )
+               cmd->set_cmd(LC_REEXPORT_DYLIB);
+       else if ( dylib->willBeUpwardDylib() && _options.useUpwardDylibs() )
+               cmd->set_cmd(LC_LOAD_UPWARD_DYLIB);
+       else
+               cmd->set_cmd(LC_LOAD_DYLIB);
+       cmd->set_cmdsize(sz);
+       cmd->set_timestamp(2);  // needs to be some constant value that is different than DylibIDLoadCommandsAtom uses
+       cmd->set_current_version(dylib->currentVersion());
+       cmd->set_compatibility_version(dylib->compatibilityVersion());
+       cmd->set_name_offset();
+       strcpy((char*)&p[sizeof(macho_dylib_command<P>)], dylib->installPath());
+       return p + sz;
+}
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyRPathLoadCommand(uint8_t* p, const char* path) const
+{
+       uint32_t sz = alignedSize(sizeof(macho_rpath_command<P>) + strlen(path) + 1);
+       macho_rpath_command<P>* cmd = (macho_rpath_command<P>*)p;
+       cmd->set_cmd(LC_RPATH);
+       cmd->set_cmdsize(sz);
+       cmd->set_path_offset();
+       strcpy((char*)&p[sizeof(macho_rpath_command<P>)], path);
+       return p + sz;
+}
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copySubFrameworkLoadCommand(uint8_t* p) const
+{
+       const char* umbrellaName = _options.umbrellaName();
+       uint32_t sz = alignedSize(sizeof(macho_sub_framework_command<P>) + strlen(umbrellaName) + 1);
+       macho_sub_framework_command<P>* cmd = (macho_sub_framework_command<P>*)p;
+       cmd->set_cmd(LC_SUB_FRAMEWORK);
+       cmd->set_cmdsize(sz);
+       cmd->set_umbrella_offset();
+       strcpy((char*)&p[sizeof(macho_sub_framework_command<P>)], umbrellaName);
+       return p + sz;
+}
+
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyAllowableClientLoadCommand(uint8_t* p, const char* client) const
+{
+       uint32_t sz = alignedSize(sizeof(macho_sub_client_command<P>) + strlen(client) + 1);
+       macho_sub_client_command<P>* cmd = (macho_sub_client_command<P>*)p;
+       cmd->set_cmd(LC_SUB_CLIENT);
+       cmd->set_cmdsize(sz);
+       cmd->set_client_offset();
+       strcpy((char*)&p[sizeof(macho_sub_client_command<P>)], client);
+       return p + sz;
+}
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyDyldEnvLoadCommand(uint8_t* p, const char* env) const
+{
+       uint32_t sz = alignedSize(sizeof(macho_dylinker_command<P>) + strlen(env) + 1);
+       macho_dylinker_command<P>* cmd = (macho_dylinker_command<P>*)p;
+       cmd->set_cmd(LC_DYLD_ENVIRONMENT);
+       cmd->set_cmdsize(sz);
+       cmd->set_name_offset();
+       strcpy((char*)&p[sizeof(macho_dylinker_command<P>)], env);
+       return p + sz;
+}
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copySubUmbrellaLoadCommand(uint8_t* p, const char* nm) const
+{
+       uint32_t sz = alignedSize(sizeof(macho_sub_umbrella_command<P>) + strlen(nm) + 1);
+       macho_sub_umbrella_command<P>* cmd = (macho_sub_umbrella_command<P>*)p;
+       cmd->set_cmd(LC_SUB_UMBRELLA);
+       cmd->set_cmdsize(sz);
+       cmd->set_sub_umbrella_offset();
+       strcpy((char*)&p[sizeof(macho_sub_umbrella_command<P>)], nm);
+       return p + sz;
+}
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copySubLibraryLoadCommand(uint8_t* p, const char* nm) const
+{
+       uint32_t sz = alignedSize(sizeof(macho_sub_library_command<P>) + strlen(nm) + 1);
+       macho_sub_library_command<P>* cmd = (macho_sub_library_command<P>*)p;
+       cmd->set_cmd(LC_SUB_LIBRARY);
+       cmd->set_cmdsize(sz);
+       cmd->set_sub_library_offset();
+       strcpy((char*)&p[sizeof(macho_sub_library_command<P>)], nm);
+       return p + sz;
+}
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyFunctionStartsLoadCommand(uint8_t* p) const
+{
+       macho_linkedit_data_command<P>* cmd = (macho_linkedit_data_command<P>*)p;
+       cmd->set_cmd(LC_FUNCTION_STARTS);
+       cmd->set_cmdsize(sizeof(macho_linkedit_data_command<P>));
+       cmd->set_dataoff(_writer.functionStartsSection->fileOffset);
+       cmd->set_datasize(_writer.functionStartsSection->size);
+       return p + sizeof(macho_linkedit_data_command<P>);
+}
+
+
+template <typename A>
+void HeaderAndLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+       macho_header<P>* mh = (macho_header<P>*)buffer;
+       bzero(buffer, this->size());
+
+       // copy mach_header
+       mh->set_magic(this->magic());
+       mh->set_cputype(this->cpuType());
+       mh->set_cpusubtype(this->cpuSubType());
+       mh->set_filetype(this->fileType());
+       mh->set_ncmds(this->commandsCount());
+       mh->set_sizeofcmds(this->size()-sizeof(macho_header<P>));
+       mh->set_flags(this->flags());
+
+       // copy load commands
+       uint8_t* p = &buffer[sizeof(macho_header<P>)];
+       
+       if ( _options.outputKind() == Options::kObjectFile )
+               p = this->copySingleSegmentLoadCommand(p);
+       else
+               p = this->copySegmentLoadCommands(p);
+       
+       if ( _hasDylibIDLoadCommand )
+               p = this->copyDylibIDLoadCommand(p);
+               
+       if ( _hasDyldInfoLoadCommand )
+               p = this->copyDyldInfoLoadCommand(p);
+               
+       if ( _hasSymbolTableLoadCommand )
+               p = this->copySymbolTableLoadCommand(p);
+
+       if ( _hasDynamicSymbolTableLoadCommand )
+               p = this->copyDynamicSymbolTableLoadCommand(p);
+       
+       if ( _hasDyldLoadCommand )
+               p = this->copyDyldLoadCommand(p);
+               
+       if ( _hasRoutinesLoadCommand ) 
+               p = this->copyRoutinesLoadCommand(p);
+               
+       if ( _hasUUIDLoadCommand )
+               p = this->copyUUIDLoadCommand(p);
+       
+       if ( _hasVersionLoadCommand )
+               p = this->copyVersionLoadCommand(p);
+
+       if ( _hasThreadLoadCommand )
+               p = this->copyThreadsLoadCommand(p);
+               
+       if ( _hasEncryptionLoadCommand )
+               p = this->copyEncryptionLoadCommand(p);
+       
+       if ( _hasSplitSegInfoLoadCommand )
+               p = this->copySplitSegInfoLoadCommand(p);
+               
+       for(uint32_t ord=1; ord <= _writer.dylibCount(); ++ord) {
+               p = this->copyDylibLoadCommand(p, _writer.dylibByOrdinal(ord));
+       }
+
+       if ( _hasRPathLoadCommands ) {
+               const std::vector<const char*>& rpaths = _options.rpaths();
+               for (std::vector<const char*>::const_iterator it = rpaths.begin(); it != rpaths.end(); ++it) {
+                       p = this->copyRPathLoadCommand(p, *it);
+               }
+       }
+       
+       if ( _hasSubFrameworkLoadCommand )
+               p = this->copySubFrameworkLoadCommand(p);
+       
+       for (std::vector<const char*>::const_iterator it = _subLibraryNames.begin(); it != _subLibraryNames.end(); ++it) {
+               p = this->copySubLibraryLoadCommand(p, *it);
+       }
+       
+       for (std::vector<const char*>::const_iterator it = _subUmbrellaNames.begin(); it != _subUmbrellaNames.end(); ++it) {
+               p = this->copySubUmbrellaLoadCommand(p, *it);
+       }
+       
+       if ( _allowableClientLoadCommmandsCount != 0 ) {
+               const std::vector<const char*>& clients = _options.allowableClients();
+               for (std::vector<const char*>::const_iterator it = clients.begin(); it != clients.end(); ++it) {
+                       p = this->copyAllowableClientLoadCommand(p, *it);
+               }
+       }
+
+       if ( _dyldEnvironExrasCount != 0 ) {
+               const std::vector<const char*>& extras = _options.dyldEnvironExtras();
+               for (std::vector<const char*>::const_iterator it = extras.begin(); it != extras.end(); ++it) {
+                       p = this->copyDyldEnvLoadCommand(p, *it);
+               }
+       }
+
+       if ( _hasFunctionStartsLoadCommand )
+               p = this->copyFunctionStartsLoadCommand(p);
+               
+}
+
+
+
+} // namespace tool 
+} // namespace ld 
+
+#endif // __HEADER_LOAD_COMMANDS_HPP__
diff --git a/src/ld/InputFiles.cpp b/src/ld/InputFiles.cpp
new file mode 100644 (file)
index 0000000..bc292bb
--- /dev/null
@@ -0,0 +1,943 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
+ *
+ * Copyright (c) 2009-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/sysctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+#include <mach/mach_time.h>
+#include <mach/vm_statistics.h>
+#include <mach/mach_init.h>
+#include <mach/mach_host.h>
+#include <dlfcn.h>
+#include <mach-o/dyld.h>
+#include <mach-o/fat.h>
+
+#include <string>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+#include <list>
+#include <algorithm>
+#include <ext/hash_map>
+#include <ext/hash_set>
+#include <dlfcn.h>
+#include <AvailabilityMacros.h>
+
+#include "Options.h"
+
+#include "InputFiles.h"
+#include "macho_relocatable_file.h"
+#include "macho_dylib_file.h"
+#include "archive_file.h"
+#include "lto_file.h"
+#include "opaque_section_file.h"
+
+
+namespace ld {
+namespace tool {
+
+
+
+
+class DSOHandleAtom : public ld::Atom {
+public:
+                                                                       DSOHandleAtom(const char* nm, ld::Atom::Scope sc, 
+                                                                                                               ld::Atom::SymbolTableInclusion inc, bool preload=false)
+                                                                               : ld::Atom(preload ? _s_section_preload : _s_section, 
+                                                                                                       ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                                                                       sc, ld::Atom::typeUnclassified, inc, true, false, false, 
+                                                                                                        ld::Atom::Alignment(1)), _name(nm) {}
+
+       virtual ld::File*                                               file() const                                    { return NULL; }
+       virtual bool                                                    translationUnitSource(const char** dir, const char** ) const 
+                                                                                                                                                       { return false; }
+       virtual const char*                                             name() const                                    { return _name; }
+       virtual uint64_t                                                size() const                                    { return 0; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const
+                                                                                                                                                       { }
+       virtual void                                                    setScope(Scope)                                 { }
+
+       virtual                                                                 ~DSOHandleAtom() {}
+       
+       static ld::Section                                              _s_section;
+       static ld::Section                                              _s_section_preload;
+       static DSOHandleAtom                                    _s_atomAll;
+       static DSOHandleAtom                                    _s_atomExecutable;
+       static DSOHandleAtom                                    _s_atomDylib;
+       static DSOHandleAtom                                    _s_atomBundle;
+       static DSOHandleAtom                                    _s_atomDyld;
+       static DSOHandleAtom                                    _s_atomObjectFile;
+       static DSOHandleAtom                                    _s_atomPreload;
+private:
+       const char*                                                             _name;
+};
+ld::Section DSOHandleAtom::_s_section("__TEXT", "__mach_header", ld::Section::typeMachHeader, true);
+ld::Section DSOHandleAtom::_s_section_preload("__HEADER", "__mach_header", ld::Section::typeMachHeader, true);
+DSOHandleAtom DSOHandleAtom::_s_atomAll("___dso_handle", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn);
+DSOHandleAtom DSOHandleAtom::_s_atomExecutable("__mh_execute_header", ld::Atom::scopeGlobal, ld::Atom::symbolTableInAndNeverStrip);
+DSOHandleAtom DSOHandleAtom::_s_atomDylib("__mh_dylib_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn);
+DSOHandleAtom DSOHandleAtom::_s_atomBundle("__mh_bundle_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn);
+DSOHandleAtom DSOHandleAtom::_s_atomDyld("__mh_dylinker_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn);
+DSOHandleAtom DSOHandleAtom::_s_atomObjectFile("__mh_object_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn);
+DSOHandleAtom DSOHandleAtom::_s_atomPreload("__mh_preload_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn, true);
+
+
+
+class PageZeroAtom : public ld::Atom {
+public:
+                                                                       PageZeroAtom(uint64_t sz)
+                                                                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                                                       ld::Atom::scopeTranslationUnit, ld::Atom::typeZeroFill, 
+                                                                                       symbolTableNotIn, true, false, false, ld::Atom::Alignment(12)),
+                                                                                       _size(sz) {}
+
+       virtual ld::File*                                               file() const                                    { return NULL; }
+       virtual bool                                                    translationUnitSource(const char** dir, const char** ) const 
+                                                                                                                                                       { return false; }
+       virtual const char*                                             name() const                                    { return "page zero"; }
+       virtual uint64_t                                                size() const                                    { return _size; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const 
+                                                                                                                                                       { }
+       virtual void                                                    setScope(Scope)                                 { }
+
+       virtual                                                                 ~PageZeroAtom() {}
+       
+       static ld::Section                                              _s_section;
+       static DSOHandleAtom                                    _s_atomAll;
+private:
+       uint64_t                                                                _size;
+};
+ld::Section PageZeroAtom::_s_section("__PAGEZERO", "__pagezero", ld::Section::typePageZero, true);
+
+
+class CustomStackAtom : public ld::Atom {
+public:
+                                                                       CustomStackAtom(uint64_t sz)
+                                                                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                                                       ld::Atom::scopeTranslationUnit, ld::Atom::typeZeroFill, 
+                                                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(12)),
+                                                                                       _size(sz) {}
+
+       virtual ld::File*                                               file() const                                    { return NULL; }
+       virtual bool                                                    translationUnitSource(const char** dir, const char** ) const 
+                                                                                                                                                       { return false; }
+       virtual const char*                                             name() const                                    { return "custom stack"; }
+       virtual uint64_t                                                size() const                                    { return _size; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const 
+                                                                                                                                                       { }
+       virtual void                                                    setScope(Scope)                                 { }
+
+       virtual                                                                 ~CustomStackAtom() {}
+       
+private:
+       uint64_t                                                                _size;
+       static ld::Section                                              _s_section;
+};
+ld::Section CustomStackAtom::_s_section("__UNIXSTACK", "__stack", ld::Section::typeStack, true);
+
+
+
+const char* InputFiles::fileArch(const uint8_t* p, unsigned len)
+{
+       const char* result = mach_o::relocatable::archName(p);
+       if ( result != NULL  )
+                return result;
+                
+       result = lto::archName(p, len);
+       if ( result != NULL  )
+                return result;
+       
+       if ( strncmp((const char*)p, "!<arch>\n", 8) == 0 )
+               return "archive";
+       
+       return "unsupported file format";        
+}
+
+
+ld::File* InputFiles::makeFile(const Options::FileInfo& info)
+{
+       // map in whole file
+       uint64_t len = info.fileLen;
+       int fd = ::open(info.path, O_RDONLY, 0);
+       if ( fd == -1 )
+               throwf("can't open file, errno=%d", errno);
+       if ( info.fileLen < 20 )
+               throw "file too small";
+
+       uint8_t* p = (uint8_t*)::mmap(NULL, info.fileLen, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
+       if ( p == (uint8_t*)(-1) )
+               throwf("can't map file, errno=%d", errno);
+
+       // if fat file, skip to architecture we want
+       // Note: fat header is always big-endian
+       bool isFatFile = false;
+       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;
+               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) {
+                               if ( (OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)_options.architecture())
+                                 && (OSSwapBigToHostInt32(archs[i].cpusubtype) == (uint32_t)_options.subArchitecture()) ) {
+                                       sliceToUse = i;
+                                       sliceFound = true;
+                                       break;
+                               }
+                       }
+               }
+               if ( !sliceFound ) {
+                       // look for any slice that matches just cpu-type
+                       for (uint32_t i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
+                               if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)_options.architecture() ) {
+                                       sliceToUse = i;
+                                       sliceFound = true;
+                                       break;
+                               }
+                       }
+               }
+               if ( sliceFound ) {
+                       uint32_t fileOffset = OSSwapBigToHostInt32(archs[sliceToUse].offset);
+                       len = OSSwapBigToHostInt32(archs[sliceToUse].size);
+                       if ( fileOffset+len > info.fileLen ) {
+                               throwf("truncated fat file. Slice from %u to %llu is past end of file with length %llu", 
+                                               fileOffset, fileOffset+len, info.fileLen);
+                       }
+                       // if requested architecture is page aligned within fat file, then remap just that portion of file
+                       if ( (fileOffset & 0x00000FFF) == 0 ) {
+                               // unmap whole file
+                               munmap((caddr_t)p, info.fileLen);
+                               // re-map just part we need
+                               p = (uint8_t*)::mmap(NULL, len, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, fileOffset);
+                               if ( p == (uint8_t*)(-1) )
+                                       throwf("can't re-map file, errno=%d", errno);
+                       }
+                       else {
+                               p = &p[fileOffset];
+                       }
+               }
+       }
+       ::close(fd);
+
+       // see if it is an object file
+       mach_o::relocatable::ParserOptions objOpts;
+       objOpts.architecture            = _options.architecture();
+       objOpts.objSubtypeMustMatch = _options.preferSubArchitecture();
+       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);
+
+       // 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);
+
+       // 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);
+       if ( dylibResult != NULL ) 
+               return this->addDylib(dylibResult, info, len);
+
+       // see if it is a static library
+       archive::ParserOptions archOpts;
+       archOpts.objOpts                                = objOpts;
+       archOpts.forceLoadThisArchive   = info.options.fForceLoad;
+       archOpts.forceLoadAll                   = _options.fullyLoadArchives();
+       archOpts.forceLoadObjC                  = _options.loadAllObjcObjectsFromArchives();
+       archOpts.verboseLoad                    = _options.whyLoad();
+       archOpts.logAllFiles                    = _options.logAllFiles();
+       ld::File* archiveResult = archive::parse(p, len, info.path, info.modTime, _nextInputOrdinal, archOpts);
+       if ( archiveResult != NULL ) 
+               return this->addArchive(archiveResult, info, len);
+
+       // 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());
+               }
+               else {
+                       const char* libLTO = "libLTO.dylib";
+                       char ldPath[PATH_MAX];
+                       char tmpPath[PATH_MAX];
+                       char libLTOPath[PATH_MAX];
+                       uint32_t bufSize = PATH_MAX;
+                       if ( _NSGetExecutablePath(ldPath, &bufSize) != -1 ) {
+                               if ( realpath(ldPath, tmpPath) != NULL ) {
+                                       char* lastSlash = strrchr(tmpPath, '/');
+                                       if ( lastSlash != NULL )
+                                               strcpy(lastSlash, "/../lib/libLTO.dylib");
+                                       libLTO = tmpPath;
+                                       if ( realpath(tmpPath, libLTOPath) != NULL ) 
+                                               libLTO = libLTOPath;
+                               }
+                       }
+                       throwf("could not process llvm bitcode object file, because %s could not be loaded", libLTO);
+               }
+       }
+
+       // error handling
+       if ( ((fat_header*)p)->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
+               throwf("missing required architecture %s in file", _options.architectureName());
+       }
+       else {
+               if ( isFatFile )
+                       throwf("file is universal but does not contain a(n) %s slice", _options.architectureName());
+               else
+                       throwf("file was built for %s which is not the architecture being linked (%s)", fileArch(p, len), _options.architectureName());
+       }
+}
+
+void InputFiles::logDylib(ld::File* file, bool indirect)
+{
+       if ( _options.traceDylibs() ) {
+               const char* fullPath = file->path();
+               char realName[MAXPATHLEN];
+               if ( realpath(fullPath, realName) != NULL )
+                       fullPath = realName;
+               const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(file);
+               if ( (dylib != NULL ) && dylib->willBeUpwardDylib() ) {
+                       // don't log upward dylibs when XBS is computing dependencies
+                       logTraceInfo("[Logging for XBS] Used upward dynamic library: %s\n", fullPath);
+               }
+               else {
+                       if ( indirect )
+                               logTraceInfo("[Logging for XBS] Used indirect dynamic library: %s\n", fullPath);
+                       else
+                               logTraceInfo("[Logging for XBS] Used dynamic library: %s\n", fullPath);
+               }
+       }
+}
+
+void InputFiles::logArchive(ld::File* file) const
+{
+       if ( _options.traceArchives() && (_archiveFilesLogged.count(file) == 0) ) {
+               // <rdar://problem/4947347> LD_TRACE_ARCHIVES should only print out when a .o is actually used from an archive
+               _archiveFilesLogged.insert(file);
+               const char* fullPath = file->path();
+               char realName[MAXPATHLEN];
+               if ( realpath(fullPath, realName) != NULL )
+                       fullPath = realName;
+               logTraceInfo("[Logging for XBS] Used static archive: %s\n", fullPath);
+       }
+}
+
+
+void InputFiles::logTraceInfo(const char* format, ...) const
+{
+       // one time open() of custom LD_TRACE_FILE
+       static int trace_file = -1;
+       if ( trace_file == -1 ) {
+               const char *trace_file_path = _options.traceOutputFile();
+               if ( trace_file_path != NULL ) {
+                       trace_file = open(trace_file_path, O_WRONLY | O_APPEND | O_CREAT, 0666);
+                       if ( trace_file == -1 )
+                               throwf("Could not open or create trace file: %s", trace_file_path);
+               }
+               else {
+                       trace_file = fileno(stderr);
+               }
+       }
+
+       char trace_buffer[MAXPATHLEN * 2];
+    va_list ap;
+       va_start(ap, format);
+       int length = vsnprintf(trace_buffer, sizeof(trace_buffer), format, ap);
+       va_end(ap);
+       char* buffer_ptr = trace_buffer;
+
+       while (length > 0) {
+               ssize_t amount_written = write(trace_file, buffer_ptr, length);
+               if(amount_written == -1)
+                       /* Failure to write shouldn't fail the build. */
+                       return;
+               buffer_ptr += amount_written;
+               length -= amount_written;
+       }
+}
+
+ld::dylib::File* InputFiles::findDylib(const char* installPath, const char* fromPath)
+{
+       //fprintf(stderr, "findDylib(%s, %s)\n", installPath, fromPath);
+       InstallNameToDylib::iterator pos = _installPathToDylibs.find(installPath);
+       if ( pos != _installPathToDylibs.end() ) {
+               return pos->second;
+       }
+       else {
+               // allow -dylib_path option to override indirect library to use
+               for (std::vector<Options::DylibOverride>::const_iterator dit = _options.dylibOverrides().begin(); dit != _options.dylibOverrides().end(); ++dit) {
+                       if ( strcmp(dit->installName,installPath) == 0 ) {
+                               try {
+                                       Options::FileInfo info = _options.findFile(dit->useInstead);
+                                       ld::File* reader = this->makeFile(info);
+                                       ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader);
+                                       if ( dylibReader != NULL ) {
+                                               //_installPathToDylibs[strdup(installPath)] = dylibReader;
+                                               this->logDylib(dylibReader, true);
+                                               return dylibReader;
+                                       }
+                                       else 
+                                               throwf("indirect dylib at %s is not a dylib", dit->useInstead);
+                               }
+                               catch (const char* msg) {
+                                       warning("ignoring -dylib_file option, %s", msg);
+                               }
+                       }
+               }
+               char newPath[MAXPATHLEN];
+               // handle @loader_path
+               if ( strncmp(installPath, "@loader_path/", 13) == 0 ) {
+                       strcpy(newPath, fromPath);
+                       char* addPoint = strrchr(newPath,'/');
+                       if ( addPoint != NULL )
+                               strcpy(&addPoint[1], &installPath[13]);
+                       else
+                               strcpy(newPath, &installPath[13]);
+                       installPath = newPath;
+               }
+               // note: @executable_path case is handled inside findFileUsingPaths()
+               // search for dylib using -F and -L paths
+               Options::FileInfo info = _options.findFileUsingPaths(installPath);
+               try {
+                       ld::File* reader = this->makeFile(info);
+                       ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader);
+                       if ( dylibReader != NULL ) {
+                               //assert(_installPathToDylibs.find(installPath) !=  _installPathToDylibs.end());
+                               //_installPathToDylibs[strdup(installPath)] = dylibReader;
+                               this->logDylib(dylibReader, true);
+                               return dylibReader;
+                       }
+                       else 
+                               throwf("indirect dylib at %s is not a dylib", info.path);
+               }
+               catch (const char* msg) {
+                       throwf("in %s, %s", info.path, msg);
+               }
+       }
+}
+
+
+
+void InputFiles::createIndirectDylibs()
+{
+       _allDirectDylibsLoaded = true;
+
+       // 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();
+               this->checkDylibClientRestrictions(it->second);
+       }
+       
+       // keep processing dylibs until no more dylibs are added
+       unsigned long lastMapSize = 0;
+       std::set<ld::dylib::File*>      dylibsProcessed;
+       while ( lastMapSize != _allDylibs.size() ) {
+               lastMapSize = _allDylibs.size();
+               // can't iterator _installPathToDylibs while modifying it, so use temp buffer
+               std::vector<ld::dylib::File*> unprocessedDylibs;
+               for (std::set<ld::dylib::File*>::iterator it=_allDylibs.begin(); it != _allDylibs.end(); it++) {
+                       if ( dylibsProcessed.count(*it) == 0 )
+                               unprocessedDylibs.push_back(*it);
+               }
+               for (std::vector<ld::dylib::File*>::iterator it=unprocessedDylibs.begin(); it != unprocessedDylibs.end(); it++) {
+                       dylibsProcessed.insert(*it);
+                       (*it)->processIndirectLibraries(this, _options.implicitlyLinkIndirectPublicDylibs());
+               }
+       }
+       
+       // go back over original dylibs and mark sub frameworks as re-exported
+       if ( _options.outputKind() == Options::kDynamicLibrary ) {
+               const char* myLeaf = strrchr(_options.installPath(), '/');
+               if ( myLeaf != NULL ) {
+                       for (std::vector<class ld::File*>::const_iterator it=_inputFiles.begin(); it != _inputFiles.end(); it++) {
+                               ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(*it);
+                               if ( dylibReader != NULL ) {
+                                       const char* childParent = dylibReader->parentUmbrella();
+                                       if ( childParent != NULL ) {
+                                               if ( strcmp(childParent, &myLeaf[1]) == 0 ) {
+                                                       // mark that this dylib will be re-exported
+                                                       dylibReader->setWillBeReExported();
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+       
+}
+
+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++;
+       }
+
+}
+
+
+void InputFiles::checkDylibClientRestrictions(ld::dylib::File* dylib)
+{
+       // Check for any restrictions on who can link with this dylib  
+       const char* dylibParentName = dylib->parentUmbrella() ;
+       const std::vector<const char*>* clients = dylib->allowableClients();
+       if ( (dylibParentName != NULL) || (clients != NULL) ) {
+               // only dylibs that are in an umbrella or have a client list need verification
+               const char* installName = _options.installPath();
+               const char* installNameLastSlash = strrchr(installName, '/');
+               bool isParent = false;
+               bool isSibling = false;
+               bool isAllowableClient = false;
+               // There are three cases:
+               if ( (dylibParentName != NULL) && (installNameLastSlash != NULL) ) {
+                       // starts after last slash
+                       const char* myName = &installNameLastSlash[1];
+                       unsigned int myNameLen = strlen(myName);
+                       if ( strncmp(myName, "lib", 3) == 0 )
+                               myName = &myName[3];
+                       // up to first dot
+                       const char* firstDot = strchr(myName, '.');
+                       if ( firstDot != NULL )
+                               myNameLen = firstDot - myName;
+                       // up to first underscore
+                       const char* firstUnderscore = strchr(myName, '_');
+                       if ( (firstUnderscore != NULL) && ((firstUnderscore - myName) < (int)myNameLen) )
+                               myNameLen = firstUnderscore - myName;
+               
+                       // case 1) The dylib has a parent umbrella, and we are creating the parent umbrella
+                       isParent = ( (strlen(dylibParentName) == myNameLen) && (strncmp(myName, dylibParentName, myNameLen) == 0) );
+                       
+                       // case 2) The dylib has a parent umbrella, and we are creating a sibling with the same parent
+                       isSibling = ( (_options.umbrellaName() != NULL) && (strcmp(_options.umbrellaName(), dylibParentName) == 0) );
+               }
+
+               if ( !isParent && !isSibling && (clients != NULL) ) {
+                       // case 3) the dylib has a list of allowable clients, and we are creating one of them
+                       const char* clientName = _options.clientName();
+                       int clientNameLen = 0;
+                       if ( clientName != NULL ) {
+                               // use client name as specified on command line
+                               clientNameLen = strlen(clientName);
+                       }
+                       else {
+                               // infer client name from output path (e.g. xxx/libfoo_variant.A.dylib --> foo, Bar.framework/Bar_variant --> Bar)
+                               clientName = installName;
+                               clientNameLen = strlen(clientName);
+                               // starts after last slash
+                               if ( installNameLastSlash != NULL )
+                                       clientName = &installNameLastSlash[1];
+                               if ( strncmp(clientName, "lib", 3) == 0 )
+                                       clientName = &clientName[3];
+                               // up to first dot
+                               const char* firstDot = strchr(clientName, '.');
+                               if ( firstDot != NULL )
+                                       clientNameLen = firstDot - clientName;
+                               // up to first underscore
+                               const char* firstUnderscore = strchr(clientName, '_');
+                               if ( (firstUnderscore != NULL) && ((firstUnderscore - clientName) < clientNameLen) )
+                                       clientNameLen = firstUnderscore - clientName;
+                       }
+
+                       // Use clientName to check if this dylib is able to link against the allowable clients.
+                       for (std::vector<const char*>::const_iterator it = clients->begin(); it != clients->end(); it++) {
+                               if ( strncmp(*it, clientName, clientNameLen) == 0 )
+                                       isAllowableClient = true;
+                       }
+               }
+       
+               if ( !isParent && !isSibling && !isAllowableClient ) {
+                       if ( dylibParentName != NULL ) {
+                               throwf("cannot link directly with %s.  Link against the umbrella framework '%s.framework' instead.", 
+                                       dylib->path(), dylibParentName);
+                       }
+                       else {
+                               throwf("cannot link directly with %s", dylib->path());
+                       }
+               }
+       }
+}
+
+
+void InputFiles::inferArchitecture(Options& opts, const char** archName)
+{
+       _inferredArch = true;
+       // scan all input files, looking for a thin .o file.
+       // the first one found is presumably the architecture to link
+       uint8_t buffer[sizeof(mach_header_64)];
+       const std::vector<Options::FileInfo>& files = opts.getInputFiles();
+       for (std::vector<Options::FileInfo>::const_iterator it = files.begin(); it != files.end(); ++it) {
+               int fd = ::open(it->path, O_RDONLY, 0);
+               if ( fd != -1 ) {
+                       ssize_t amount = read(fd, buffer, sizeof(buffer));
+                       ::close(fd);
+                       if ( amount >= (ssize_t)sizeof(buffer) ) {
+                               cpu_type_t type;
+                               cpu_subtype_t subtype;
+                               if ( mach_o::relocatable::isObjectFile(buffer, &type, &subtype) ) {
+                                       opts.setArchitecture(type, subtype);
+                                       *archName = opts.architectureName();
+                                       return;
+                               }
+                       }
+               }
+       }
+
+       // no thin .o files found, so default to same architecture this tool was built as
+       warning("-arch not specified");
+#if __ppc__
+       opts.setArchitecture(CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL);
+#elif __i386__
+       opts.setArchitecture(CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL);
+#elif __ppc64__
+       opts.setArchitecture(CPU_TYPE_POWERPC64, CPU_SUBTYPE_POWERPC_ALL);
+#elif __x86_64__
+       opts.setArchitecture(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL);
+#elif __arm__
+       opts.setArchitecture(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6);
+#else
+       #error unknown default architecture
+#endif
+       *archName = opts.architectureName();
+}
+
+
+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)
+{
+//     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 ( files.size() == 0 )
+               throw "no object files specified";
+       // add all direct object, archives, and dylibs
+       _inputFiles.reserve(files.size());
+       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));
+               }
+               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);
+                       }
+               }
+       }
+
+       this->createIndirectDylibs();
+       this->createOpaqueFileSections();
+}
+
+
+
+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;
+}
+
+
+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;
+}
+
+
+ld::File* InputFiles::addDylib(ld::dylib::File* reader, const Options::FileInfo& info, uint64_t mappedLen)
+{
+       _allDylibs.insert(reader);
+       
+       if ( (reader->installPath() == NULL) && !info.options.fBundleLoader ) {
+               // this is a "blank" stub
+               // silently ignore it
+               return reader;
+       }
+       // store options about how dylib will be used in dylib itself
+       if ( info.options.fWeakImport )
+               reader->setWillBeWeakLinked();
+       if ( info.options.fReExport )
+               reader->setWillBeReExported();
+       if ( info.options.fUpward ) {
+               if ( _options.outputKind() == Options::kDynamicLibrary ) 
+                       reader->setWillBeUpwardDylib();
+               else 
+                       warning("ignoring upward dylib option for %s\n", info.path);
+       }
+       if ( info.options.fLazyLoad )
+               reader->setWillBeLazyLoadedDylb();
+       
+       // add to map of loaded dylibs
+       const char* installPath = reader->installPath();
+       if ( installPath != NULL ) {
+               InstallNameToDylib::iterator pos = _installPathToDylibs.find(installPath);
+               if ( pos == _installPathToDylibs.end() ) {
+                       _installPathToDylibs[strdup(installPath)] = reader;
+               }
+               else {
+                       bool dylibOnCommandLineTwice = ( strcmp(pos->second->path(), reader->path()) == 0 );
+                       bool isSymlink = false;
+                       // ignore if this is a symlink to a dylib we've already loaded
+                       if ( !dylibOnCommandLineTwice ) {
+                               char existingDylibPath[PATH_MAX];
+                               if ( realpath(pos->second->path(), existingDylibPath) != NULL ) {
+                                       char newDylibPath[PATH_MAX];
+                                       if ( realpath(reader->path(), newDylibPath) != NULL ) {
+                                               isSymlink = ( strcmp(existingDylibPath, newDylibPath) == 0 );
+                                       }
+                               }
+                       }
+                       if ( !dylibOnCommandLineTwice && !isSymlink )
+                               warning("dylibs with same install name: %s and %s", pos->second->path(), reader->path());
+               }
+       }
+       else if ( info.options.fBundleLoader )
+               _bundleLoader = reader;
+
+       // log direct readers
+       if ( !_allDirectDylibsLoaded ) 
+               this->logDylib(reader, false);
+
+       // bump ordinal
+       _nextInputOrdinal++;
+
+       // update stats
+       _totalDylibsLoaded++;
+
+       return reader;
+}
+
+
+bool InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler) const
+{
+       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::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::kStaticExecutable:
+                               // add implicit __dso_handle label
+                               handler.doAtom(DSOHandleAtom::_s_atomExecutable);
+                               handler.doAtom(DSOHandleAtom::_s_atomAll);
+                               break;
+                       case Options::kPreload:
+                               // add implicit __mh_preload_header label
+                               handler.doAtom(DSOHandleAtom::_s_atomPreload);
+                               break;
+                       case Options::kObjectFile:
+                               handler.doAtom(DSOHandleAtom::_s_atomObjectFile);
+                               break;
+                       case Options::kKextBundle:
+                               // add implicit __dso_handle label
+                               handler.doAtom(DSOHandleAtom::_s_atomAll);
+                               break;
+               }
+       }
+       return didSomething;
+}
+
+
+bool InputFiles::searchLibraries(const char* name, bool searchDylibs, bool searchArchives, ld::File::AtomHandler& handler) const
+{
+       // 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);
+               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
+                       }
+               }
+               else if ( searchArchives && (dylibFile == NULL) ) {
+                       if ( file->justInTimeforEachAtom(name, handler) ) {
+                               if ( _options.traceArchives() ) 
+                                       logArchive(file);
+                               // found definition in static library, done
+                               return true;
+                       }
+               }
+       }
+
+       // search indirect dylibs
+       if ( searchDylibs ) {
+               for (InstallNameToDylib::const_iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); ++it) {
+                       ld::dylib::File* dylibFile = it->second;
+                       bool searchThisDylib = false;
+                       if ( _options.nameSpace() == Options::kTwoLevelNameSpace ) {
+                               // for two level namesapce, just check all implicitly linked dylibs
+                               searchThisDylib = dylibFile->implicitlyLinked() && !dylibFile->explicitlyLinked();
+                       }
+                       else {
+                               // for flat namespace, check all indirect dylibs
+                               searchThisDylib = ! dylibFile->explicitlyLinked();
+                       }
+                       if ( searchThisDylib ) {
+                               //fprintf(stderr, "searchLibraries(%s), looking in implicitly 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
+                               }
+                       }                       
+               }
+       }
+
+       return false;
+}
+
+
+bool InputFiles::searchWeakDefInDylib(const char* name) const
+{
+       // search all relevant dylibs to see if any of a weak-def with this name
+       for (InstallNameToDylib::const_iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); ++it) {
+               ld::dylib::File* dylibFile = it->second;
+               if ( dylibFile->implicitlyLinked() || dylibFile->explicitlyLinked() ) {
+                       if ( dylibFile->hasWeakExternals() && dylibFile->hasWeakDefinition(name) ) {
+                               return true;
+                       }
+               }
+       }
+       return false;
+}
+
+void InputFiles::dylibs(ld::Internal& state)
+{
+       bool dylibsOK;
+       switch ( _options.outputKind() ) {
+               case Options::kDynamicExecutable:
+               case Options::kDynamicLibrary:
+               case Options::kDynamicBundle:
+                       dylibsOK = true;
+                       break;
+               case Options::kStaticExecutable:
+               case Options::kDyld:
+               case Options::kPreload:
+               case Options::kObjectFile:
+               case Options::kKextBundle:
+                       dylibsOK = false;
+                       break;
+       }
+
+       // add command line dylibs in order
+       for (std::vector<ld::File*>::const_iterator it=_inputFiles.begin(); it != _inputFiles.end(); ++it) {
+               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);
+                       else
+                               warning("unexpected dylib (%s) on link line", dylibFile->path());
+               }
+       }
+       // add implicitly linked dylibs
+       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);
+               }
+       }
+       // and -bundle_loader
+       state.bundleLoader = _bundleLoader;
+}
+
+
+} // namespace tool 
+} // namespace ld 
+
diff --git a/src/ld/InputFiles.h b/src/ld/InputFiles.h
new file mode 100644 (file)
index 0000000..1565515
--- /dev/null
@@ -0,0 +1,115 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __INPUT_FILES_H__
+#define __INPUT_FILES_H__
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/sysctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+#include <mach/mach_time.h>
+#include <mach/vm_statistics.h>
+#include <mach/mach_init.h>
+#include <mach/mach_host.h>
+#include <dlfcn.h>
+#include <mach-o/dyld.h>
+
+#include <vector>
+
+#include "Options.h"
+#include "ld.hpp"
+
+namespace ld {
+namespace tool {
+
+class InputFiles : public ld::dylib::File::DylibHandler
+{
+public:
+                                                               InputFiles(Options& opts, const char** archName);
+
+       // implementation from ld::dylib::File::DylibHandler
+       virtual ld::dylib::File*        findDylib(const char* installPath, const char* fromPath);
+       
+       // iterates all atoms in initial files
+       bool                                            forEachInitialAtom(ld::File::AtomHandler&) const;
+       // searches libraries for name
+       bool                                            searchLibraries(const char* name, bool searchDylibs, bool searchArchives, ld::File::AtomHandler&) const;
+       // see if any linked dylibs export a weak def of symbol
+       bool                                            searchWeakDefInDylib(const char* name) const;
+       // copy dylibs to link with in command line order
+       void                                            dylibs(ld::Internal& state);
+       
+       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;
+       
+       
+private:
+       void                                            inferArchitecture(Options& opts, const char** archName);
+       const char*                                     fileArch(const uint8_t* p, unsigned len);
+       ld::File*                                       makeFile(const Options::FileInfo& info);
+       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);
+       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();
+
+       class CStringEquals {
+       public:
+               bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+       };
+       typedef __gnu_cxx::hash_map<const char*, ld::dylib::File*, __gnu_cxx::hash<const char*>, CStringEquals> InstallNameToDylib;
+
+       const Options&                          _options;
+       std::vector<ld::File*>          _inputFiles;
+       mutable std::set<class ld::File*>       _archiveFilesLogged;
+       InstallNameToDylib                      _installPathToDylibs;
+       std::set<ld::dylib::File*>      _allDylibs;
+       ld::dylib::File*                        _bundleLoader;
+       mutable uint32_t                        _nextInputOrdinal;
+       bool                                            _allDirectDylibsLoaded;
+       bool                                            _inferredArch;
+};
+
+} // namespace tool 
+} // namespace ld 
+
+#endif // __INPUT_FILES_H__
diff --git a/src/ld/LTOReader.hpp b/src/ld/LTOReader.hpp
deleted file mode 100644 (file)
index 2e560cc..0000000
+++ /dev/null
@@ -1,742 +0,0 @@
-/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
- *
- * Copyright (c) 2006-2009 Apple Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-#ifndef __LTO_READER_H__
-#define __LTO_READER_H__
-
-#include <stdlib.h>
-#include <mach-o/dyld.h>
-#include <vector>
-#include <ext/hash_set>
-#include <ext/hash_map>
-
-#include "MachOFileAbstraction.hpp"
-#include "Architectures.hpp"
-#include "ObjectFile.h"
-#include "Options.h"
-
-#include "llvm-c/lto.h"
-
-
-namespace lto {
-
-
-//
-// Reference handles Atom references. These references facilitate 
-// symbol resolution.
-//
-
-class Reference : public ObjectFile::Reference
-{
-public:
-                                                                               Reference(const char* name) : fTargetName(name), fTargetAtom(NULL) { }
-                                                                               Reference(ObjectFile::Atom& atom) : fTargetName(NULL), fTargetAtom(&atom) { }
-
-       bool                                                            isTargetUnbound() const                         { return fTargetAtom == NULL; }
-       bool                                                            isFromTargetUnbound() const             { return true; }
-       uint8_t                                                         getKind() const                                         { return 0; }
-       uint64_t                                                        getFixUpOffset() const                          { return 0; }
-       const char *                                            getTargetName() const                           { return fTargetName; }
-       ObjectFile::Atom&                                       getTarget() const                                       { return *fTargetAtom; }
-       uint64_t                                                        getTargetOffset() const                         { return 0; }
-       bool                                                            hasFromTarget() const                           { return false; }
-       ObjectFile::Atom&                                       getFromTarget() const                           { return *((ObjectFile::Atom*)NULL); }
-       const char *                                            getFromTargetName() const                       { return NULL; }
-       uint64_t                                                        getFromTargetOffset() const             { return 0; }
-       TargetBinding                                           getTargetBinding() const;
-       TargetBinding                                           getFromTargetBinding() const  { return kDontBind; }
-       void                                                            setTarget (ObjectFile::Atom& a, uint64_t offset) 
-                                                                               { fTargetAtom = &a; }
-       void                                                            setFromTarget(ObjectFile::Atom &a)      { }
-       const char *                                            getDescription() const;
-
-private:
-       const char *                                            fTargetName;
-       ObjectFile::Atom *                                      fTargetAtom;
-};
-
-
-ObjectFile::Reference::TargetBinding Reference::getTargetBinding() const 
-{ 
-       if ( fTargetAtom == NULL ) 
-               return kUnboundByName;
-       else if ( fTargetName == NULL ) 
-               return kBoundDirectly;
-       else
-               return kBoundByName;
-}
-
-const char* Reference::getDescription() const
-{ 
-       static char temp[256];
-       strcpy(temp, "reference to ");
-       if ( fTargetName != NULL )
-               strcat(temp, fTargetName);
-       else
-               strcat(temp, fTargetAtom->getDisplayName());
-       return temp; 
-}
-
-
-class Segment : public ObjectFile::Segment
-{
-public:
-                                                                               Segment(const char* name, bool readable, bool writable, bool executable, bool fixedAddress)
-                                                                                       : fName(name), fReadable(readable), fWritable(writable), fExecutable(executable), fFixedAddress(fixedAddress) {}
-       virtual const char*                                     getName() const                                         { return fName; }
-       virtual bool                                            isContentReadable() const                       { return fReadable; }
-       virtual bool                                            isContentWritable() const                       { return fWritable; }
-       virtual bool                                            isContentExecutable() const                     { return fExecutable; }
-       virtual bool                                            hasFixedAddress() const                         { return fFixedAddress; }
-
-       static Segment                                          fgBootstrapSegment;
-
-private:
-       const char*                                                     fName;
-       const bool                                                      fReadable;
-       const bool                                                      fWritable;
-       const bool                                                      fExecutable;
-       const bool                                                      fFixedAddress;
-};
-
-Segment        Segment:: fgBootstrapSegment("__TEMP", true, false, false, false);
-  
-       
-         
-
-//
-// Atom acts as a proxy Atom for the symbols that are exported by LLVM bitcode file. Initially,
-// Reader creates Atoms to allow linker proceed with usual symbol resolution phase. After
-// optimization is performed, real Atoms are created for these symobls. However these real Atoms
-// are not inserted into global symbol table. Atom holds real Atom and forwards appropriate
-// methods to real atom.
-//
-class Atom : public ObjectFile::Atom
-{
-public:
-                                                                                               Atom(class Reader& owner, const char* name, Scope, DefinitionKind, uint8_t alignment, ObjectFile::Atom& internalAtom);
-       
-       ObjectFile::Reader*                                                     getFile() const                         { return (ObjectFile::Reader*)&fOwner; }
-       bool                                                                            getTranslationUnitSource (const char **dir, const char **name) const 
-                                                                                                                                                       { return fRealAtom->getTranslationUnitSource(dir, name); }
-       const char *                                                            getName () const                        { return fName; }
-       const char *                                                            getDisplayName() const          { return this->getName(); }
-       Scope                                                                           getScope() const                        { return (fRealAtom ? fRealAtom->getScope() : fScope); }
-       DefinitionKind                                                          getDefinitionKind() const       { return (fRealAtom ? fRealAtom->getDefinitionKind() : fKind); }
-       SymbolTableInclusion                                            getSymbolTableInclusion() const 
-                                                                                                                                                       { return (fRealAtom ? fRealAtom->getSymbolTableInclusion() : ObjectFile::Atom::kSymbolTableIn); }
-       bool                                                                            dontDeadStrip() const           { return false; }
-       bool                                                                            isZeroFill() const                      { return (fRealAtom ? fRealAtom->isZeroFill() : false); }
-       bool                                                                            isThumb() const                         { return false; }
-       uint64_t                                                                        getSize() const                         { return (fRealAtom ? fRealAtom->getSize() : 0); }
-       std::vector<ObjectFile::Reference*>&            getReferences() const 
-                                                                                                                                                       { return (fRealAtom ? fRealAtom->getReferences() : (std::vector<ObjectFile::Reference*>&)fReferences); }
-       bool                                                                            mustRemainInSection() const { return fRealAtom->mustRemainInSection(); }
-       const char *                                                            getSectionName() const          { return (fRealAtom ? fRealAtom->getSectionName() : NULL); }
-       // Linker::optimize() sets section for this atom, not fRealAtom. Use this Atom's fSection.
-       class ObjectFile::Section *                                     getSection() const                      { return fSection; }
-       ObjectFile::Segment&                                            getSegment() const                      { return (fRealAtom ? fRealAtom->getSegment() : Segment::fgBootstrapSegment); }
-       uint32_t                                                                        getOrdinal() const                      { return (fRealAtom ? fRealAtom->getOrdinal() : 0); }
-       ObjectFile::Atom&                                                       getFollowOnAtom() const         { return fRealAtom->getFollowOnAtom(); }
-       std::vector<ObjectFile::LineInfo>*                      getLineInfo() const             { return (fRealAtom ? fRealAtom->getLineInfo() : NULL); }
-       ObjectFile::Alignment                                           getAlignment() const            { return (fRealAtom ? fRealAtom->getAlignment() : ObjectFile::Alignment(fAlignment)); }
-       void                                                                            copyRawContent(uint8_t buffer[]) const 
-                                                                                                                                                       { if (fRealAtom) fRealAtom->copyRawContent(buffer); }
-       void                                                                            setScope(Scope s)                       { if (fRealAtom) fRealAtom->setScope(s); else fScope = s; }
-
-       void                                                                            setRealAtom (ObjectFile::Atom *atom) 
-                                                                                                                                                       { fRealAtom = atom; }
-       ObjectFile::Atom *                                                      getRealAtom() { return fRealAtom; }
-       void                                                                            addReference(ObjectFile::Reference *ref) 
-                                                                                                                                                       { fReferences.push_back(ref); }
-
-       void                                                                            setSectionOffset(uint64_t offset) { fSectionOffset = offset; if (fRealAtom) fRealAtom->setSectionOffset(offset); }
-       void                                                                            setSection(class ObjectFile::Section* sect) { fSection = sect; if (fRealAtom) fRealAtom->setSection(sect); }
-                                                                                                                                                       
-private:
-       class Reader&                                                           fOwner;
-       const char*                                                                     fName;
-       ObjectFile::Atom::Scope                                         fScope;
-       ObjectFile::Atom::DefinitionKind                        fKind;
-       uint8_t                                                                         fAlignment;
-       ObjectFile::Atom*                                                       fRealAtom;
-       std::vector<ObjectFile::Reference*>             fReferences;
-};
-
-
-Atom::Atom(class Reader& owner, const char* name, Scope scope, DefinitionKind kind, uint8_t alignment, ObjectFile::Atom& internalAtom) 
-: fOwner(owner), fName(name), fScope(scope), fKind(kind), fAlignment(alignment), fRealAtom(NULL)
-{
-       // every Atom references the InternalAtom for its reader
-       fReferences.push_back(new Reference(internalAtom));
-}
-
-
-//
-// ld64 only tracks non-internal symbols from an llvm bitcode file.  
-// We model this by having an InternalAtom which represent all internal functions and data.
-// All non-interal symbols from a bitcode file are represented by a Atom
-// and each Atom has a reference to the InternalAtom.  The InternalAtom
-// also has references to each symbol external to the bitcode file. 
-//
-class InternalAtom : public ObjectFile::Atom
-{
-public:
-                                                                                               InternalAtom(class Reader& owner) : fOwner(owner) {}
-
-       ObjectFile::Reader *                                            getFile() const                         { return (ObjectFile::Reader*)&fOwner; }
-       bool                                                                            getTranslationUnitSource (const char **dir, const char **name) const 
-                                                                                                                                                       { return false; }
-       const char *                                                            getName () const                        { return "__llvm-internal-atom";        }
-       const char *                                                            getDisplayName() const          { return "llvm bitcode"; }
-       Scope                                                                           getScope() const                        { return scopeTranslationUnit; }
-       DefinitionKind                                                          getDefinitionKind() const   { return kRegularDefinition; }
-       SymbolTableInclusion                                            getSymbolTableInclusion() const { return kSymbolTableNotIn; }
-       bool                                                                            dontDeadStrip() const           { return false; }
-       bool                                                                            isZeroFill() const                      { return false; }
-       bool                                                                            isThumb() const                         { return false; }
-       uint64_t                                                                        getSize() const                         { return 0; }
-       std::vector<ObjectFile::Reference*>&            getReferences() const           { return  (std::vector<ObjectFile::Reference*>&)fReferences; }
-       bool                                                                            mustRemainInSection() const { return false; }
-       const char *                                                            getSectionName() const          { return NULL; }
-       class ObjectFile::Section *                                     getSection() const                      { return NULL; }
-       ObjectFile::Segment&                                            getSegment() const                      { return Segment::fgBootstrapSegment; }
-       uint32_t                                                                        getOrdinal() const          { return 0; }
-       ObjectFile::Atom&                                                       getFollowOnAtom() const         { return *((ObjectFile::Atom*)NULL); }
-       std::vector<ObjectFile::LineInfo>*                      getLineInfo() const             { return NULL; }
-       ObjectFile::Alignment                                           getAlignment() const            { return ObjectFile::Alignment(0); }
-       void                                                                            copyRawContent(uint8_t buffer[]) const { }
-       void                                                                            setScope(Scope s)                       { }
-
-       void                                                                            addReference(const char* targetName);
-       
-private:
-       class Reader&                                                           fOwner;
-       std::vector<ObjectFile::Reference*>             fReferences;
-};
-
-
-void InternalAtom::addReference(const char* name)
-{
-       fReferences.push_back(new Reference(name));
-}
-
-
-
-
-class RemovableAtoms
-{
-public:
-       RemovableAtoms(std::set<ObjectFile::Atom*>& iAtoms) : fAtoms(iAtoms) {}
-
-       bool operator()(ObjectFile::Atom*& atom) const {
-               return ( fAtoms.count(atom) != 0 );
-       }
-
-private:
-       std::set<ObjectFile::Atom*>& fAtoms;
-};
-
-
-
-//
-// LLVM bitcode file reader
-//
-class Reader : public ObjectFile::Reader
-{
-public:
-       static bool                                                                             validFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture);
-       static const char*                                                              fileKind(const uint8_t* fileContent);
-       static bool                                                                             loaded() { return (::lto_get_version() != NULL); }
-                                                                                                       Reader(const uint8_t* fileContent, uint64_t fileLength, 
-                                                                                                                               const char* path, time_t modTime, 
-                                                                                                                               const ObjectFile::ReaderOptions&, cpu_type_t arch);
-       virtual                                                                                 ~Reader();
-       
-       virtual std::vector<class ObjectFile::Atom*>&   getAtoms()                              { return (std::vector<class ObjectFile::Atom*>&)(fAtoms); }
-       virtual std::vector<class ObjectFile::Atom*>*   getJustInTimeAtomsFor(const char* name) { return NULL; }
-       virtual const char*                                                             getPath()                               { return fPath; }
-       virtual time_t                                                                  getModificationTime()   { return fModTime; }
-       virtual ObjectFile::Reader::DebugInfoKind               getDebugInfoKind()              { return kDebugInfoNone; }
-       virtual std::vector<Stab>*                                              getStabs()                              { return NULL; }
-       virtual bool                                                                    optimize(const std::vector<ObjectFile::Atom*>& allAtoms, std::vector<ObjectFile::Atom*>& newAtoms, 
-                                                                                                                               std::vector<const char*>& additionalUndefines, const std::set<ObjectFile::Atom*>&,
-                                                                                                                               std::vector<ObjectFile::Atom*>& newDeadAtoms,
-                                                                                                                               uint32_t nextInputOrdinal, 
-                                                                                                                               ObjectFile::Reader* writer, ObjectFile::Atom* entryPointAtom,
-                                                                                                                               const std::vector<const char*>& llvmOptions,
-                                                                                                                               bool allGlobalsAReDeadStripRoots,
-                                                                                                                               int outputKind, bool verbose, bool saveTemps, const char* outputFilePath,
-                                                                                                                               bool pie, bool allowTextRelocs);
-
-private:
-
-       class CStringEquals
-       {
-       public:
-               bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
-       };
-       typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals>  CStringSet;
-       typedef __gnu_cxx::hash_map<const char*, Atom*, __gnu_cxx::hash<const char*>, CStringEquals> CStringToAtom;
-       
-       ObjectFile::Reader*                                                             makeMachOReader(const uint8_t* p, size_t len, uint32_t nextInputOrdinal);
-       static const char*                                                              tripletPrefixForArch(cpu_type_t);
-
-       cpu_type_t                                                                              fArchitecture;
-       const char*                                                                             fPath;
-       time_t                                                                                  fModTime;
-       lto_module_t                                                                    fModule;
-       std::vector<ObjectFile::Atom*>                                  fAtoms;
-       InternalAtom                                                                    fInternalAtom;
-       const ObjectFile::ReaderOptions&                                fReaderOptions;
-       static std::set<Reader*>                                                fgReaders;
-       static bool                                                                             fgOptimized;
-};
-
-bool                                   Reader::fgOptimized = false;
-std::set<Reader*>              Reader::fgReaders;
-
-
-Reader::~Reader()
-{
-       if ( fModule != NULL )
-               ::lto_module_dispose(fModule);
-}
-
-Reader::Reader(const uint8_t* fileContent, uint64_t fileLength, const char* path, time_t modTime, 
-                               const ObjectFile::ReaderOptions& options, cpu_type_t arch)
-       : fArchitecture(arch), fPath(strdup(path)), fModTime(modTime), fInternalAtom(*this), fReaderOptions(options)
-{
-       fgReaders.insert(this);
-
-       fModule = ::lto_module_create_from_memory(fileContent, fileLength);
-    if ( fModule == NULL )
-               throwf("could not parse object file %s: %s", path, lto_get_error_message());
-       
-       fAtoms.push_back(&fInternalAtom);
-       
-       uint32_t count = ::lto_module_get_num_symbols(fModule);
-       for (uint32_t i=0; i < count; ++i) {
-               const char* name = ::lto_module_get_symbol_name(fModule, i);
-               lto_symbol_attributes attr = lto_module_get_symbol_attribute(fModule, i);
-
-               // <rdar://problem/6378110> LTO doesn't like dtrace symbols
-               // ignore dtrace static probes for now
-               // later when codegen is done and a mach-o file is produces the probes will be processed
-               if ( (strncmp(name, "___dtrace_probe$", 16) == 0) || (strncmp(name, "___dtrace_isenabled$", 20) == 0) )
-                       continue;
-                               
-               ObjectFile::Atom::DefinitionKind kind;
-               switch ( attr & LTO_SYMBOL_DEFINITION_MASK ) {
-                       case LTO_SYMBOL_DEFINITION_REGULAR:
-                               kind = ObjectFile::Atom::kRegularDefinition;
-                               break;
-                       case LTO_SYMBOL_DEFINITION_TENTATIVE:
-                               kind = ObjectFile::Atom::kTentativeDefinition;
-                               break;
-                       case LTO_SYMBOL_DEFINITION_WEAK:
-                               kind = ObjectFile::Atom::kWeakDefinition;
-                               break;
-                       case LTO_SYMBOL_DEFINITION_UNDEFINED:
-                       case LTO_SYMBOL_DEFINITION_WEAKUNDEF:
-                               kind = ObjectFile::Atom::kExternalDefinition;
-                               break;
-                       default:
-                               throwf("unknown definition kind for symbol %s in bitcode file %s", name, path);
-               }
-
-               // make LLVM atoms for definitions and a reference for undefines
-               if ( kind != ObjectFile::Atom::kExternalDefinition ) {
-                       ObjectFile::Atom::Scope scope;
-                       switch ( attr & LTO_SYMBOL_SCOPE_MASK) {
-                               case LTO_SYMBOL_SCOPE_INTERNAL:
-                                       scope = ObjectFile::Atom::scopeTranslationUnit;
-                                       break;
-                               case LTO_SYMBOL_SCOPE_HIDDEN:
-                                       scope = ObjectFile::Atom::scopeLinkageUnit;
-                                       break;
-                               case LTO_SYMBOL_SCOPE_DEFAULT:
-                                       scope = ObjectFile::Atom::scopeGlobal;
-                                       break;
-                               default:
-                                       throwf("unknown scope for symbol %s in bitcode file %s", name, path);
-                       }
-                       // only make atoms for non-internal symbols 
-                       if ( scope == ObjectFile::Atom::scopeTranslationUnit )
-                               continue;
-                       uint8_t alignment = (attr & LTO_SYMBOL_ALIGNMENT_MASK);
-                       // make Atom
-                       fAtoms.push_back(new Atom(*this, name, scope, kind, alignment, fInternalAtom));
-               }
-               else {
-                       // add to list of external references
-                       fInternalAtom.addReference(name);
-               }
-       }
-}
-
-const char* Reader::tripletPrefixForArch(cpu_type_t arch)
-{
-       switch (arch) {
-               case CPU_TYPE_POWERPC:
-                       return "powerpc-";
-               case CPU_TYPE_POWERPC64:
-                       return "powerpc64-";
-               case CPU_TYPE_I386:
-                       return "i386-";
-               case CPU_TYPE_X86_64:
-                       return "x86_64-";
-               case CPU_TYPE_ARM:
-                       return "arm";
-       }
-       return "";
-}
-
-bool Reader::validFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture)
-{
-       return ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, tripletPrefixForArch(architecture));
-}
-
-const char* Reader::fileKind(const uint8_t* p)
-{
-       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_POWERPC:
-                               return "ppc";
-                       case CPU_TYPE_I386:
-                               return "i386";
-                       case CPU_TYPE_X86_64:
-                               return "x86_64";
-                       case CPU_TYPE_ARM:
-                               return "arm";
-               }
-               return "unknown bitcode architecture";
-       }
-       return NULL;
-}
-
-bool Reader::optimize(const std::vector<ObjectFile::Atom *>& allAtoms, std::vector<ObjectFile::Atom*>& newAtoms, 
-                                                       std::vector<const char*>& additionalUndefines, const std::set<ObjectFile::Atom*>& deadAtoms,
-                                                       std::vector<ObjectFile::Atom*>& newlyDeadAtoms,
-                                                       uint32_t nextInputOrdinal,  ObjectFile::Reader* writer, ObjectFile::Atom* entryPointAtom,
-                                                       const std::vector<const char*>& llvmOptions,
-                                                       bool allGlobalsAReDeadStripRoots,
-                                                       int okind, bool verbose, bool saveTemps, const char* outputFilePath,
-                                                       bool pie, bool allowTextRelocs)
-{ 
-       // this method is call on all Readers.  We want the first call to trigger optimization
-       // across all Readers and the subsequent calls to do nothing.
-       if ( fgOptimized ) 
-               return false;
-       fgOptimized = true;
-       
-       Options::OutputKind outputKind = (Options::OutputKind)okind; // HACK to work around upward dependency
-
-       // print out LTO version string if -v was used
-       if ( verbose )
-               fprintf(stderr, "%s\n", lto_get_version());
-       
-       // create optimizer and add each Reader
-       lto_code_gen_t generator = ::lto_codegen_create();
-       for (std::set<Reader*>::iterator it=fgReaders.begin(); it != fgReaders.end(); ++it) {
-               if ( ::lto_codegen_add_module(generator, (*it)->fModule) )
-                       throwf("lto: could not merge in %s because %s", (*it)->fPath, ::lto_get_error_message());
-       }
-
-       // add any -mllvm command line options
-       for (std::vector<const char*>::const_iterator it=llvmOptions.begin(); it != llvmOptions.end(); ++it) {
-               ::lto_codegen_debug_options(generator, *it);
-       }
-
-       // The atom graph uses directed edges (references). Collect all references where 
-       // originating atom is not part of any LTO Reader. This allows optimizer to optimize an 
-       // external (i.e. not originated from same .o file) reference if all originating atoms are also 
-       // defined in llvm bitcode file.
-       CStringSet nonLLVMRefs;
-       CStringToAtom llvmAtoms;
-    bool hasNonllvmAtoms = false;
-       for (std::vector<ObjectFile::Atom*>::const_iterator it = allAtoms.begin(); it != allAtoms.end(); ++it) {
-               ObjectFile::Atom* atom = *it;
-               // only look at references come from an atom that is not an llvm atom
-               if ( fgReaders.count((Reader*)(atom->getFile())) == 0 ) {
-                               // remember if we've seen any atoms not from an llvm reader and not from the writer
-                               if ( atom->getFile() != writer )
-                                       hasNonllvmAtoms = true;
-                               std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
-                               for (std::vector<ObjectFile::Reference*>::iterator ri=refs.begin(), re=refs.end(); ri != re; ++ri) {
-                                       ObjectFile::Reference* ref = *ri;
-                                       // add target name to set if target is an llvm atom
-                                       if ( (ref->getTargetName() != NULL) && (fgReaders.count((Reader*)(ref->getTarget().getFile())) != 0) ) {
-                                               nonLLVMRefs.insert(ref->getTargetName());
-                               }
-                       }
-               }
-               else {
-                       const char* name = atom->getName();
-                       if ( name != NULL )
-                               llvmAtoms[name] = (Atom*)atom;
-               }
-       }
-       // if entry  point is in a llvm bitcode file, it must be preserved by LTO
-       if ( entryPointAtom != NULL ) {
-               if ( fgReaders.count((Reader*)(entryPointAtom->getFile())) != 0 ) 
-                       nonLLVMRefs.insert(entryPointAtom->getName());
-       }
-       
-       // deadAtoms are the atoms that the linker coalesced.  For instance weak or tentative definitions
-       // overriden by another atom.  If any of these deadAtoms are llvm atoms and they were replaced
-       // with a mach-o atom, we need to tell the lto engine to preserve (not optimize away) its dead 
-       // atom so that the linker can replace it with the mach-o one later.
-       CStringToAtom deadllvmAtoms;
-       for (std::set<ObjectFile::Atom*>::iterator it = deadAtoms.begin(); it != deadAtoms.end(); ++it) {
-               ObjectFile::Atom* atom = *it;
-               if ( fgReaders.count((Reader*)(atom->getFile())) != 0 ) {
-                       const char* name = atom->getName();
-                       ::lto_codegen_add_must_preserve_symbol(generator, name);
-                       deadllvmAtoms[name] = (Atom*)atom;
-               }
-       }
-
-       
-       // tell code generator about symbols that must be preserved
-       for (CStringToAtom::iterator it = llvmAtoms.begin(); it != llvmAtoms.end(); ++it) {
-               const char* name = it->first;
-               Atom* atom = it->second;
-               // Include llvm Symbol in export list if it meets one of following two conditions
-               // 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->getScope() == ObjectFile::Atom::scopeGlobal) ) 
-                       ::lto_codegen_add_must_preserve_symbol(generator, name);
-               else if ( nonLLVMRefs.find(name) != nonLLVMRefs.end() ) 
-                       ::lto_codegen_add_must_preserve_symbol(generator, name);
-       }
-       
-    // special case running ld -r on all bitcode files to produce another bitcode file (instead of mach-o)
-    if ( (outputKind == Options::kObjectFile) && !hasNonllvmAtoms ) {
-               if ( ! ::lto_codegen_write_merged_modules(generator, outputFilePath) ) {
-                       // HACK, no good way to tell linker we are all done, so just quit
-                       exit(0);
-               }
-               warning("could not produce merged bitcode file");
-    }
-    
-       // set code-gen model
-       lto_codegen_model model = LTO_CODEGEN_PIC_MODEL_DYNAMIC;
-       switch ( outputKind ) {
-               case Options::kDynamicExecutable:
-               case Options::kPreload:
-                       if ( pie )
-                               model = LTO_CODEGEN_PIC_MODEL_DYNAMIC;
-                       else
-                               model = LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC;
-                       break;
-               case Options::kDynamicLibrary:
-               case Options::kDynamicBundle:
-               case Options::kObjectFile: // ?? Is this appropriate ?
-               case Options::kDyld:
-               case Options::kKextBundle:
-                       if ( allowTextRelocs )
-                               model = LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC;
-                       else
-                               model = LTO_CODEGEN_PIC_MODEL_DYNAMIC;
-                       break;
-               case Options::kStaticExecutable:
-                       // darwin x86_64 "static" code model is really dynamic code model
-                       if ( fArchitecture == CPU_TYPE_X86_64 )
-                               model = LTO_CODEGEN_PIC_MODEL_DYNAMIC;
-                       else
-                               model = LTO_CODEGEN_PIC_MODEL_STATIC;
-                       break;
-       }
-       if ( ::lto_codegen_set_pic_model(generator, model) )
-               throwf("could not create set codegen model: %s", lto_get_error_message());
-
-    // if requested, save off merged bitcode file
-    if ( saveTemps ) {
-        char tempBitcodePath[MAXPATHLEN];
-        strcpy(tempBitcodePath, outputFilePath);
-        strcat(tempBitcodePath, ".lto.bc");
-        ::lto_codegen_write_merged_modules(generator, tempBitcodePath);
-    }
-
-#if LTO_API_VERSION >= 3
-       // find assembler next to linker
-       char path[PATH_MAX];
-       uint32_t bufSize = PATH_MAX;
-       if ( _NSGetExecutablePath(path, &bufSize) != -1 ) {
-               char* lastSlash = strrchr(path, '/');
-               if ( lastSlash != NULL ) {
-                       strcpy(lastSlash+1, "as");
-                       struct stat statInfo;
-                       if ( stat(path, &statInfo) == 0 )
-                               ::lto_codegen_set_assembler_path(generator, path);
-               }
-       }
-#endif
-       // run code generator
-       size_t machOFileLen;
-       const uint8_t* machOFile = (uint8_t*)::lto_codegen_compile(generator, &machOFileLen);
-       if ( machOFile == NULL ) 
-               throwf("could not do LTO codegen: %s", ::lto_get_error_message());
-       
-    // if requested, save off temp mach-o file
-    if ( saveTemps ) {
-        char tempMachoPath[MAXPATHLEN];
-        strcpy(tempMachoPath, outputFilePath);
-        strcat(tempMachoPath, ".lto.o");
-        int fd = ::open(tempMachoPath, O_CREAT | O_WRONLY | O_TRUNC, 0666);
-               if ( fd != -1) {
-                       ::write(fd, machOFile, machOFileLen);
-                       ::close(fd);
-               }
-               //      save off merged bitcode file
-               char tempOptBitcodePath[MAXPATHLEN];
-        strcpy(tempOptBitcodePath, outputFilePath);
-        strcat(tempOptBitcodePath, ".lto.opt.bc");
-        ::lto_codegen_write_merged_modules(generator, tempOptBitcodePath);
-       }
-
-       // parse generated mach-o file into a MachOReader
-       ObjectFile::Reader* machoReader = this->makeMachOReader(machOFile, machOFileLen, nextInputOrdinal);
-       
-       // sync generated mach-o atoms with existing atoms ld knows about
-       std::vector<ObjectFile::Atom*> machoAtoms = machoReader->getAtoms();
-       for (std::vector<ObjectFile::Atom *>::iterator it = machoAtoms.begin(); it != machoAtoms.end(); ++it) {
-               ObjectFile::Atom* atom = *it;
-               const char* name = atom->getName();
-               if ( name != NULL ) {
-                       CStringToAtom::iterator pos = llvmAtoms.find(name);
-                       if ( pos != llvmAtoms.end() ) {
-                               // turn Atom into a proxy for this mach-o atom
-                               pos->second->setRealAtom(atom);
-                       }
-                       else {
-                               // an atom of this name was not in the allAtoms list the linker gave us
-                               if ( deadllvmAtoms.find(name) != deadllvmAtoms.end() ) {
-                                       // this corresponding to an atom that the linker coalesced away.  Ignore it
-                                       // Make sure there any dependent atoms are also marked dead
-                                       std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
-                                       for (std::vector<ObjectFile::Reference*>::iterator ri=refs.begin(), re=refs.end(); ri != re; ++ri) {
-                                               ObjectFile::Reference* ref = *ri;
-                                               if ( ref->getKind() == 2 /*kGroupSubordinate*/ ) {      // FIX FIX
-                                                       ObjectFile::Atom* targ = &ref->getTarget();
-                                                       deadllvmAtoms[targ->getName()] = (Atom*)atom;
-                                               }
-                                       }
-                               }
-                               else
-                               {
-                                       // this is something new that lto conjured up, tell ld its new
-                                       newAtoms.push_back(atom);
-                               }
-                       }
-               }
-               else {
-                       // ld only knew about named atoms, so this one must be new
-                       newAtoms.push_back(atom);
-               }
-               std::vector<class ObjectFile::Reference*>& references = atom->getReferences();
-               for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); ++rit) {
-                       ObjectFile::Reference* ref = *rit;
-                       const char* targetName = ref->getTargetName();
-                       CStringToAtom::iterator pos;
-                       if (targetName != NULL) {
-                               switch ( ref->getTargetBinding() ) {
-                                       case ObjectFile::Reference::kUnboundByName:
-                                               // accumulate unbounded references so that ld can bound them.
-                                               additionalUndefines.push_back(targetName);
-                                               break;
-                                       case ObjectFile::Reference::kBoundDirectly:
-                                       case ObjectFile::Reference::kBoundByName:
-                                               // If mach-o atom is referencing another mach-o atom then 
-                                               // reference is not going through Atom proxy. Fix it here to ensure that all
-                                               // llvm symbol references always go through Atom proxy.
-                                               pos = llvmAtoms.find(targetName);
-                                               if ( pos != llvmAtoms.end() )
-                                                       ref->setTarget(*pos->second, ref->getTargetOffset());
-                                               break;
-                                       case ObjectFile::Reference::kDontBind:
-                                               break;
-                               }
-                       }
-               }
-       }
-               
-       // Remove InternalAtoms from ld
-       for (std::set<Reader*>::iterator it=fgReaders.begin(); it != fgReaders.end(); ++it) {
-               newlyDeadAtoms.push_back(&((*it)->fInternalAtom));
-       }
-       // Remove Atoms from ld if code generator optimized them away
-       for (CStringToAtom::iterator li = llvmAtoms.begin(), le = llvmAtoms.end(); li != le; ++li) {
-               // check if setRealAtom() called on this Atom
-               if ( li->second->getRealAtom() == NULL )
-                       newlyDeadAtoms.push_back(li->second);
-       }
-       
-       return true;
-}
-
-
-ObjectFile::Reader* Reader::makeMachOReader(const uint8_t* p, size_t len, uint32_t nextInputOrdinal) 
-{
-       switch ( fArchitecture ) {
-               case CPU_TYPE_POWERPC:
-                       if ( mach_o::relocatable::Reader<ppc>::validFile(p) )
-                               return new mach_o::relocatable::Reader<ppc>(p, "/tmp/lto.o", 0, fReaderOptions, nextInputOrdinal);
-                       break;
-               case CPU_TYPE_POWERPC64:
-                       if ( mach_o::relocatable::Reader<ppc64>::validFile(p) )
-                               return new mach_o::relocatable::Reader<ppc64>(p, "/tmp/lto.o", 0, fReaderOptions, nextInputOrdinal);
-                       break;
-               case CPU_TYPE_I386:
-                       if ( mach_o::relocatable::Reader<x86>::validFile(p) )
-                               return new mach_o::relocatable::Reader<x86>(p, "/tmp/lto.o", 0, fReaderOptions, nextInputOrdinal);
-                       break;
-               case CPU_TYPE_X86_64:
-                       if ( mach_o::relocatable::Reader<x86_64>::validFile(p) )
-                               return new mach_o::relocatable::Reader<x86_64>(p, "/tmp/lto.o", 0, fReaderOptions, nextInputOrdinal);
-                       break;
-               case CPU_TYPE_ARM:
-                       if ( mach_o::relocatable::Reader<arm>::validFile(p) )
-                               return new mach_o::relocatable::Reader<arm>(p, "/tmp/lto.o", 0, fReaderOptions, nextInputOrdinal);
-                       break;
-       }
-       throw "LLVM LTO, file is not of required architecture";
-}
-
-}; // namespace lto
-
-extern void printLTOVersion(Options& opts);
-
-void printLTOVersion(Options& opts) {
-       const char* vers = lto_get_version();
-       if ( vers != NULL )
-               fprintf(stderr, "%s\n", vers);
-}
-
-
-#endif
-
diff --git a/src/ld/LinkEdit.hpp b/src/ld/LinkEdit.hpp
new file mode 100644 (file)
index 0000000..d905a3d
--- /dev/null
@@ -0,0 +1,1306 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
+ *
+ * Copyright (c) 2009-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@
+ */
+
+#ifndef __LINKEDIT_HPP__
+#define __LINKEDIT_HPP__
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+
+#include <vector>
+
+#include "Options.h"
+#include "ld.hpp"
+#include "Architectures.hpp"
+#include "MachOFileAbstraction.hpp"
+
+namespace ld {
+namespace tool {
+
+class ByteStream {
+private:
+       std::vector<uint8_t>            _data;
+public:
+       std::vector<uint8_t>& bytes() { return _data; }
+       unsigned long size() const { return _data.size(); }
+       void reserve(unsigned long l) { _data.reserve(l); }
+       const uint8_t* start() const { return &_data[0]; }
+
+       void append_uleb128(uint64_t value) {
+               uint8_t byte;
+               do {
+                       byte = value & 0x7F;
+                       value &= ~0x7F;
+                       if ( value != 0 )
+                               byte |= 0x80;
+                       _data.push_back(byte);
+                       value = value >> 7;
+               } while( byte >= 0x80 );
+       }
+       
+       void append_sleb128(int64_t value) {
+               bool isNeg = ( value < 0 );
+               uint8_t byte;
+               bool more;
+               do {
+                       byte = value & 0x7F;
+                       value = value >> 7;
+                       if ( isNeg ) 
+                               more = ( (value != -1) || ((byte & 0x40) == 0) );
+                       else
+                               more = ( (value != 0) || ((byte & 0x40) != 0) );
+                       if ( more )
+                               byte |= 0x80;
+                       _data.push_back(byte);
+               } 
+               while( more );
+       }
+       
+       void append_string(const char* str) {
+               for (const char* s = str; *s != '\0'; ++s)
+                       _data.push_back(*s);
+               _data.push_back('\0');
+       }
+       
+       void append_byte(uint8_t byte) {
+               _data.push_back(byte);
+       }
+       
+       static unsigned int     uleb128_size(uint64_t value) {
+               uint32_t result = 0;
+               do {
+                       value = value >> 7;
+                       ++result;
+               } while ( value != 0 );
+               return result;
+       }
+       
+       void pad_to_size(unsigned int alignment) {
+               while ( (_data.size() % alignment) != 0 )
+                       _data.push_back(0);
+       }
+};
+
+
+class LinkEditAtom : public ld::Atom
+{
+public:
+
+       // overrides of ld::Atom
+       virtual ld::File*                                                       file() const            { return NULL; }
+       virtual bool                                                            translationUnitSource(const char** dir, const char** nm) const
+                                                                                                                                       { return false; }
+       virtual uint64_t                                                        objectAddress() const { return 0; }
+       virtual uint64_t                                                        size() const;
+       virtual void                                                            copyRawContent(uint8_t buffer[]) const; 
+
+       virtual void                                                            encode() const = 0;
+       
+                                                                                               LinkEditAtom(const Options& opts, ld::Internal& state, 
+                                                                                                                               OutputFile& writer, const ld::Section& sect,
+                                                                                                                               unsigned int pointerSize)
+                                                                                               : ld::Atom(sect, ld::Atom::definitionRegular,
+                                                                                                                       ld::Atom::combineNever, ld::Atom::scopeTranslationUnit,
+                                                                                                                       ld::Atom::typeUnclassified, ld::Atom::symbolTableNotIn,
+                                                                                                                       false, false, false, ld::Atom::Alignment(log2(pointerSize))), 
+                                                                                                               _options(opts), _state(state), _writer(writer), 
+                                                                                                               _encoded(false) { }
+protected:
+       const Options&                          _options;
+       ld::Internal&                           _state;
+       OutputFile&                                     _writer;
+       mutable ByteStream                      _encodedData;
+       mutable bool                            _encoded;
+};
+
+uint64_t LinkEditAtom::size() const
+{
+       assert(_encoded);
+       return _encodedData.size();
+}
+
+void LinkEditAtom::copyRawContent(uint8_t buffer[]) const
+{
+       assert(_encoded);
+       memcpy(buffer, _encodedData.start(), _encodedData.size());
+}
+
+
+
+
+template <typename A>
+class RebaseInfoAtom : public LinkEditAtom
+{
+public:
+                                                                                               RebaseInfoAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+                                                                                                       : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { _encoded = true; }
+
+       // overrides of ld::Atom
+       virtual const char*                                                     name() const            { return "rebase info"; }
+       // overrides of LinkEditAtom
+       virtual void                                                            encode() const;
+
+private:
+       struct rebase_tmp
+       {
+               rebase_tmp(uint8_t op, uint64_t p1, uint64_t p2=0) : opcode(op), operand1(p1), operand2(p2) {}
+               uint8_t         opcode;
+               uint64_t        operand1;
+               uint64_t        operand2;
+       };
+
+       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 RebaseInfoAtom<A>::_s_section("__LINKEDIT", "__rebase", ld::Section::typeLinkEdit, true);
+
+
+template <typename A>
+void RebaseInfoAtom<A>::encode() const
+{
+       // omit relocs if this was supposed to be PIE but PIE not possible
+       if ( _options.positionIndependentExecutable() && this->_writer.pieDisabled ) 
+               return;
+
+       // sort rebase info by type, then address
+       std::vector<OutputFile::RebaseInfo>& info = this->_writer._rebaseInfo;
+       std::sort(info.begin(), info.end());
+       
+       // convert to temp encoding that can be more easily optimized
+       std::vector<rebase_tmp> mid;
+       uint64_t curSegStart = 0;
+       uint64_t curSegEnd = 0;
+       uint32_t curSegIndex = 0;       
+       uint8_t type = 0;
+       uint64_t address = (uint64_t)(-1);
+       for (std::vector<OutputFile::RebaseInfo>::iterator it = info.begin(); it != info.end(); ++it) {
+               if ( type != it->_type ) {
+                       mid.push_back(rebase_tmp(REBASE_OPCODE_SET_TYPE_IMM, it->_type));
+                       type = it->_type;
+               }
+               if ( address != it->_address ) {
+                       if ( (it->_address < curSegStart) || ( it->_address >= curSegEnd) ) {
+                               if ( ! this->_writer.findSegment(this->_state, it->_address, &curSegStart, &curSegEnd, &curSegIndex) )
+                                       throw "binding address outside range of any segment";
+                               mid.push_back(rebase_tmp(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, curSegIndex, it->_address - curSegStart));
+                       }
+                       else {
+                               mid.push_back(rebase_tmp(REBASE_OPCODE_ADD_ADDR_ULEB, it->_address-address));
+                       }
+                       address = it->_address;
+               }
+               mid.push_back(rebase_tmp(REBASE_OPCODE_DO_REBASE_ULEB_TIMES, 1));
+               address += sizeof(pint_t);
+       }
+       mid.push_back(rebase_tmp(REBASE_OPCODE_DONE, 0));
+
+       // optimize phase 1, compress packed runs of pointers
+       rebase_tmp* dst = &mid[0];
+       for (const rebase_tmp* src = &mid[0]; src->opcode != REBASE_OPCODE_DONE; ++src) {
+               if ( (src->opcode == REBASE_OPCODE_DO_REBASE_ULEB_TIMES) && (src->operand1 == 1) ) {
+                       *dst = *src++;
+                       while (src->opcode == REBASE_OPCODE_DO_REBASE_ULEB_TIMES ) {
+                               dst->operand1 += src->operand1;
+                               ++src;
+                       }
+                       --src;
+                       ++dst;
+               }
+               else {
+                       *dst++ = *src;
+               }
+       }
+       dst->opcode = REBASE_OPCODE_DONE;
+
+       // optimize phase 2, combine rebase/add pairs
+       dst = &mid[0];
+       for (const rebase_tmp* src = &mid[0]; src->opcode != REBASE_OPCODE_DONE; ++src) {
+               if ( (src->opcode == REBASE_OPCODE_DO_REBASE_ULEB_TIMES) 
+                               && (src->operand1 == 1) 
+                               && (src[1].opcode == REBASE_OPCODE_ADD_ADDR_ULEB)) {
+                       dst->opcode = REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB;
+                       dst->operand1 = src[1].operand1;
+                       ++src;
+                       ++dst;
+               }
+               else {
+                       *dst++ = *src;
+               }
+       }
+       dst->opcode = REBASE_OPCODE_DONE;
+       
+       // optimize phase 3, compress packed runs of REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB with
+       // same addr delta into one REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
+       dst = &mid[0];
+       for (const rebase_tmp* src = &mid[0]; src->opcode != REBASE_OPCODE_DONE; ++src) {
+               uint64_t delta = src->operand1;
+               if ( (src->opcode == REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB) 
+                               && (src[1].opcode == REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB) 
+                               && (src[2].opcode == REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB) 
+                               && (src[1].operand1 == delta) 
+                               && (src[2].operand1 == delta) ) {
+                       // found at least three in a row, this is worth compressing
+                       dst->opcode = REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB;
+                       dst->operand1 = 1;
+                       dst->operand2 = delta;
+                       ++src;
+                       while ( (src->opcode == REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB)
+                                       && (src->operand1 == delta) ) {
+                               dst->operand1++;
+                               ++src;
+                       }
+                       --src;
+                       ++dst;
+               }
+               else {
+                       *dst++ = *src;
+               }
+       }
+       dst->opcode = REBASE_OPCODE_DONE;
+       
+       // optimize phase 4, use immediate encodings
+       for (rebase_tmp* p = &mid[0]; p->opcode != REBASE_OPCODE_DONE; ++p) {
+               if ( (p->opcode == REBASE_OPCODE_ADD_ADDR_ULEB) 
+                       && (p->operand1 < (15*sizeof(pint_t)))
+                       && ((p->operand1 % sizeof(pint_t)) == 0) ) {
+                       p->opcode = REBASE_OPCODE_ADD_ADDR_IMM_SCALED;
+                       p->operand1 = p->operand1/sizeof(pint_t);
+               }
+               else if ( (p->opcode == REBASE_OPCODE_DO_REBASE_ULEB_TIMES) && (p->operand1 < 15) ) {
+                       p->opcode = REBASE_OPCODE_DO_REBASE_IMM_TIMES;
+               }
+       }
+
+       // convert to compressed encoding
+       const static bool log = false;
+       this->_encodedData.reserve(info.size()*2);
+       bool done = false;
+       for (typename std::vector<rebase_tmp>::iterator it = mid.begin(); !done && it != mid.end() ; ++it) {
+               switch ( it->opcode ) {
+                       case REBASE_OPCODE_DONE:
+                               if ( log ) fprintf(stderr, "REBASE_OPCODE_DONE()\n");
+                               done = true;
+                               break;
+                       case REBASE_OPCODE_SET_TYPE_IMM:
+                               if ( log ) fprintf(stderr, "REBASE_OPCODE_SET_TYPE_IMM(%lld)\n", it->operand1);
+                               this->_encodedData.append_byte(REBASE_OPCODE_SET_TYPE_IMM | it->operand1);
+                               break;
+                       case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+                               if ( log ) fprintf(stderr, "REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%lld, 0x%llX)\n", it->operand1, it->operand2);
+                               this->_encodedData.append_byte(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | it->operand1);
+                               this->_encodedData.append_uleb128(it->operand2);
+                               break;
+                       case REBASE_OPCODE_ADD_ADDR_ULEB:
+                               if ( log ) fprintf(stderr, "REBASE_OPCODE_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
+                               this->_encodedData.append_byte(REBASE_OPCODE_ADD_ADDR_ULEB);
+                               this->_encodedData.append_uleb128(it->operand1);
+                               break;
+                       case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
+                               if ( log ) fprintf(stderr, "REBASE_OPCODE_ADD_ADDR_IMM_SCALED(%lld=0x%llX)\n", it->operand1, it->operand1*sizeof(pint_t));
+                               this->_encodedData.append_byte(REBASE_OPCODE_ADD_ADDR_IMM_SCALED | it->operand1 );
+                               break;
+                       case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
+                               if ( log ) fprintf(stderr, "REBASE_OPCODE_DO_REBASE_IMM_TIMES(%lld)\n", it->operand1);
+                               this->_encodedData.append_byte(REBASE_OPCODE_DO_REBASE_IMM_TIMES | it->operand1);
+                               break;
+                       case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
+                               if ( log ) fprintf(stderr, "REBASE_OPCODE_DO_REBASE_ULEB_TIMES(%lld)\n", it->operand1);
+                               this->_encodedData.append_byte(REBASE_OPCODE_DO_REBASE_ULEB_TIMES);
+                               this->_encodedData.append_uleb128(it->operand1);
+                               break;
+                       case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
+                               if ( log ) fprintf(stderr, "REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
+                               this->_encodedData.append_byte(REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB);
+                               this->_encodedData.append_uleb128(it->operand1);
+                               break;
+                       case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
+                               if ( log ) fprintf(stderr, "REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB(%lld, %lld)\n", it->operand1, it->operand2);
+                               this->_encodedData.append_byte(REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB);
+                               this->_encodedData.append_uleb128(it->operand1);
+                               this->_encodedData.append_uleb128(it->operand2);
+                               break;
+               }
+       }
+       
+               
+       // align to pointer size
+       this->_encodedData.pad_to_size(sizeof(pint_t));
+
+       this->_encoded = true;
+
+       if (log) fprintf(stderr, "total rebase info size = %ld\n", this->_encodedData.size());
+}
+
+
+template <typename A>
+class BindingInfoAtom : public LinkEditAtom
+{
+public:
+                                                                                               BindingInfoAtom(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 "binding 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 binding_tmp
+       {
+               binding_tmp(uint8_t op, uint64_t p1, uint64_t p2=0, const char* s=NULL) 
+                       : opcode(op), operand1(p1), operand2(p2), name(s) {}
+               uint8_t         opcode;
+               uint64_t        operand1;
+               uint64_t        operand2;
+               const char*     name;
+       };
+
+       static ld::Section                      _s_section;
+};
+
+template <typename A>
+ld::Section BindingInfoAtom<A>::_s_section("__LINKEDIT", "__binding", ld::Section::typeLinkEdit, true);
+
+
+template <typename A>
+void BindingInfoAtom<A>::encode() const
+{
+       // sort by library, symbol, type, then address
+       std::vector<OutputFile::BindingInfo>& info = this->_writer._bindingInfo;
+       std::sort(info.begin(), info.end());
+       
+       // convert to temp encoding that can be more easily optimized
+       std::vector<binding_tmp> mid;
+       uint64_t curSegStart = 0;
+       uint64_t curSegEnd = 0;
+       uint32_t curSegIndex = 0;       
+       int ordinal = 0x80000000;
+       const char* symbolName = NULL;
+       uint8_t type = 0;
+       uint64_t address = (uint64_t)(-1);
+       int64_t addend = 0;
+       for (std::vector<OutputFile::BindingInfo>::const_iterator it = info.begin(); it != info.end(); ++it) {
+               if ( ordinal != it->_libraryOrdinal ) {
+                       if ( it->_libraryOrdinal <= 0 ) {
+                               // special lookups are encoded as negative numbers in BindingInfo
+                               mid.push_back(binding_tmp(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM, it->_libraryOrdinal));
+                       }
+                       else {
+                               mid.push_back(binding_tmp(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB, it->_libraryOrdinal));
+                       }
+                       ordinal = it->_libraryOrdinal;
+               }
+               if ( symbolName != it->_symbolName ) {
+                       mid.push_back(binding_tmp(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM, it->_flags, 0, it->_symbolName));
+                       symbolName = it->_symbolName;
+               }
+               if ( type != it->_type ) {
+                       mid.push_back(binding_tmp(BIND_OPCODE_SET_TYPE_IMM, it->_type));
+                       type = it->_type;
+               }
+               if ( address != it->_address ) {
+                       if ( (it->_address < curSegStart) || ( it->_address >= curSegEnd) ) {
+                               if ( ! this->_writer.findSegment(this->_state, it->_address, &curSegStart, &curSegEnd, &curSegIndex) )
+                                       throw "binding address outside range of any segment";
+                               mid.push_back(binding_tmp(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, curSegIndex, it->_address - curSegStart));
+                       }
+                       else {
+                               mid.push_back(binding_tmp(BIND_OPCODE_ADD_ADDR_ULEB, it->_address-address));
+                       }
+                       address = it->_address;
+               }
+               if ( addend != it->_addend ) {
+                       mid.push_back(binding_tmp(BIND_OPCODE_SET_ADDEND_SLEB, it->_addend));
+                       addend = it->_addend;
+               }
+               mid.push_back(binding_tmp(BIND_OPCODE_DO_BIND, 0));
+               address += sizeof(pint_t);
+       }
+       mid.push_back(binding_tmp(BIND_OPCODE_DONE, 0));
+
+
+       // optimize phase 1, combine bind/add pairs
+       binding_tmp* dst = &mid[0];
+       for (const binding_tmp* src = &mid[0]; src->opcode != BIND_OPCODE_DONE; ++src) {
+               if ( (src->opcode == BIND_OPCODE_DO_BIND) 
+                               && (src[1].opcode == BIND_OPCODE_ADD_ADDR_ULEB) ) {
+                       dst->opcode = BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB;
+                       dst->operand1 = src[1].operand1;
+                       ++src;
+                       ++dst;
+               }
+               else {
+                       *dst++ = *src;
+               }
+       }
+       dst->opcode = BIND_OPCODE_DONE;
+
+       // optimize phase 2, compress packed runs of BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB with
+       // same addr delta into one BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
+       dst = &mid[0];
+       for (const binding_tmp* src = &mid[0]; src->opcode != BIND_OPCODE_DONE; ++src) {
+               uint64_t delta = src->operand1;
+               if ( (src->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB) 
+                               && (src[1].opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB) 
+                               && (src[1].operand1 == delta) ) {
+                       // found at least two in a row, this is worth compressing
+                       dst->opcode = BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB;
+                       dst->operand1 = 1;
+                       dst->operand2 = delta;
+                       ++src;
+                       while ( (src->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
+                                       && (src->operand1 == delta) ) {
+                               dst->operand1++;
+                               ++src;
+                       }
+                       --src;
+                       ++dst;
+               }
+               else {
+                       *dst++ = *src;
+               }
+       }
+       dst->opcode = BIND_OPCODE_DONE;
+       
+       // optimize phase 3, use immediate encodings
+       for (binding_tmp* p = &mid[0]; p->opcode != REBASE_OPCODE_DONE; ++p) {
+               if ( (p->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB) 
+                       && (p->operand1 < (15*sizeof(pint_t)))
+                       && ((p->operand1 % sizeof(pint_t)) == 0) ) {
+                       p->opcode = BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED;
+                       p->operand1 = p->operand1/sizeof(pint_t);
+               }
+               else if ( (p->opcode == BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB) && (p->operand1 <= 15) ) {
+                       p->opcode = BIND_OPCODE_SET_DYLIB_ORDINAL_IMM;
+               }
+       }       
+       dst->opcode = BIND_OPCODE_DONE;
+
+       // convert to compressed encoding
+       const static bool log = false;
+       this->_encodedData.reserve(info.size()*2);
+       bool done = false;
+       for (typename std::vector<binding_tmp>::iterator it = mid.begin(); !done && it != mid.end() ; ++it) {
+               switch ( it->opcode ) {
+                       case BIND_OPCODE_DONE:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_DONE()\n");
+                               done = true;
+                               break;
+                       case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%lld)\n", it->operand1);
+                               this->_encodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | it->operand1);
+                               break;
+                       case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%lld)\n", it->operand1);
+                               this->_encodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
+                               this->_encodedData.append_uleb128(it->operand1);
+                               break;
+                       case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%lld)\n", it->operand1);
+                               this->_encodedData.append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | (it->operand1 & BIND_IMMEDIATE_MASK));
+                               break;
+                       case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%0llX, %s)\n", it->operand1, it->name);
+                               this->_encodedData.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | it->operand1);
+                               this->_encodedData.append_string(it->name);
+                               break;
+                       case BIND_OPCODE_SET_TYPE_IMM:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_SET_TYPE_IMM(%lld)\n", it->operand1);
+                               this->_encodedData.append_byte(BIND_OPCODE_SET_TYPE_IMM | it->operand1);
+                               break;
+                       case BIND_OPCODE_SET_ADDEND_SLEB:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", it->operand1);
+                               this->_encodedData.append_byte(BIND_OPCODE_SET_ADDEND_SLEB);
+                               this->_encodedData.append_sleb128(it->operand1);
+                               break;
+                       case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%lld, 0x%llX)\n", it->operand1, it->operand2);
+                               this->_encodedData.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | it->operand1);
+                               this->_encodedData.append_uleb128(it->operand2);
+                               break;
+                       case BIND_OPCODE_ADD_ADDR_ULEB:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
+                               this->_encodedData.append_byte(BIND_OPCODE_ADD_ADDR_ULEB);
+                               this->_encodedData.append_uleb128(it->operand1);
+                               break;
+                       case BIND_OPCODE_DO_BIND:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND()\n");
+                               this->_encodedData.append_byte(BIND_OPCODE_DO_BIND);
+                               break;
+                       case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
+                               this->_encodedData.append_byte(BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB);
+                               this->_encodedData.append_uleb128(it->operand1);
+                               break;
+                       case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(%lld=0x%llX)\n", it->operand1, it->operand1*sizeof(pint_t));
+                               this->_encodedData.append_byte(BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED | it->operand1 );
+                               break;
+                       case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%lld, %lld)\n", it->operand1, it->operand2);
+                               this->_encodedData.append_byte(BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB);
+                               this->_encodedData.append_uleb128(it->operand1);
+                               this->_encodedData.append_uleb128(it->operand2);
+                               break;
+               }
+       }
+       
+       // align to pointer size
+       this->_encodedData.pad_to_size(sizeof(pint_t));
+
+       this->_encoded = true;
+
+       if (log) fprintf(stderr, "total binding info size = %ld\n", this->_encodedData.size());
+}
+
+
+
+template <typename A>
+class WeakBindingInfoAtom : public LinkEditAtom
+{
+public:
+                                                                                               WeakBindingInfoAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+                                                                                                       : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { _encoded = true; }
+
+       // overrides of ld::Atom
+       virtual const char*                                                     name() const            { return "weak binding 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 WeakBindingSorter
+       {       
+                bool operator()(const OutputFile::BindingInfo& left, const OutputFile::BindingInfo& right)
+                {
+                       // sort by symbol, type, address
+                       if ( left._symbolName != right._symbolName )
+                               return ( strcmp(left._symbolName, right._symbolName) < 0 );
+                       if ( left._type != right._type )
+                               return  (left._type < right._type);
+                       return  (left._address < right._address);
+                }
+       };
+       
+       struct binding_tmp
+       {
+               binding_tmp(uint8_t op, uint64_t p1, uint64_t p2=0, const char* s=NULL) 
+                       : opcode(op), operand1(p1), operand2(p2), name(s) {}
+               uint8_t         opcode;
+               uint64_t        operand1;
+               uint64_t        operand2;
+               const char*     name;
+       };
+
+       static ld::Section                      _s_section;
+};
+
+template <typename A>
+ld::Section WeakBindingInfoAtom<A>::_s_section("__LINKEDIT", "__weak_binding", ld::Section::typeLinkEdit, true);
+
+
+template <typename A>
+void WeakBindingInfoAtom<A>::encode() const
+{
+       // sort by symbol, type, address
+       std::vector<OutputFile::BindingInfo>& info = this->_writer._weakBindingInfo;
+       if ( info.size() == 0 ) {
+               // short circuit if no weak binding needed
+               this->_encoded = true;
+               return;
+       }
+       std::sort(info.begin(), info.end(), WeakBindingSorter());
+       
+       // convert to temp encoding that can be more easily optimized
+       std::vector<binding_tmp> mid;
+       mid.reserve(info.size());
+       uint64_t curSegStart = 0;
+       uint64_t curSegEnd = 0;
+       uint32_t curSegIndex = 0;       
+       const char* symbolName = NULL;
+       uint8_t type = 0;
+       uint64_t address = (uint64_t)(-1);
+       int64_t addend = 0;
+       for (typename std::vector<OutputFile::BindingInfo>::const_iterator it = info.begin(); it != info.end(); ++it) {
+               if ( symbolName != it->_symbolName ) {
+                       mid.push_back(binding_tmp(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM, it->_flags, 0, it->_symbolName));
+                       symbolName = it->_symbolName;
+               }
+               // non-weak symbols just have BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
+               // weak symbols have SET_SEG, ADD_ADDR, SET_ADDED, DO_BIND
+               if ( it->_type != BIND_TYPE_OVERRIDE_OF_WEAKDEF_IN_DYLIB ) {
+                       if ( type != it->_type ) {
+                               mid.push_back(binding_tmp(BIND_OPCODE_SET_TYPE_IMM, it->_type));
+                               type = it->_type;
+                       }
+                       if ( address != it->_address ) {
+                               if ( (it->_address < curSegStart) || ( it->_address >= curSegEnd) ) {
+                                       if ( ! this->_writer.findSegment(this->_state, it->_address, &curSegStart, &curSegEnd, &curSegIndex) )
+                                               throw "binding address outside range of any segment";
+                                       mid.push_back(binding_tmp(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, curSegIndex, it->_address - curSegStart));
+                               }
+                               else {
+                                       mid.push_back(binding_tmp(BIND_OPCODE_ADD_ADDR_ULEB, it->_address-address));
+                               }
+                               address = it->_address;
+                       }
+                       if ( addend != it->_addend ) {
+                               mid.push_back(binding_tmp(BIND_OPCODE_SET_ADDEND_SLEB, it->_addend));
+                               addend = it->_addend;
+                       }
+                       mid.push_back(binding_tmp(BIND_OPCODE_DO_BIND, 0));
+                       address += sizeof(pint_t);
+               }
+       }
+       mid.push_back(binding_tmp(BIND_OPCODE_DONE, 0));
+
+
+       // optimize phase 1, combine bind/add pairs
+       binding_tmp* dst = &mid[0];
+       for (const binding_tmp* src = &mid[0]; src->opcode != BIND_OPCODE_DONE; ++src) {
+               if ( (src->opcode == BIND_OPCODE_DO_BIND) 
+                               && (src[1].opcode == BIND_OPCODE_ADD_ADDR_ULEB) ) {
+                       dst->opcode = BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB;
+                       dst->operand1 = src[1].operand1;
+                       ++src;
+                       ++dst;
+               }
+               else {
+                       *dst++ = *src;
+               }
+       }
+       dst->opcode = BIND_OPCODE_DONE;
+
+       // optimize phase 2, compress packed runs of BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB with
+       // same addr delta into one BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
+       dst = &mid[0];
+       for (const binding_tmp* src = &mid[0]; src->opcode != BIND_OPCODE_DONE; ++src) {
+               uint64_t delta = src->operand1;
+               if ( (src->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB) 
+                               && (src[1].opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB) 
+                               && (src[1].operand1 == delta) ) {
+                       // found at least two in a row, this is worth compressing
+                       dst->opcode = BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB;
+                       dst->operand1 = 1;
+                       dst->operand2 = delta;
+                       ++src;
+                       while ( (src->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
+                                       && (src->operand1 == delta) ) {
+                               dst->operand1++;
+                               ++src;
+                       }
+                       --src;
+                       ++dst;
+               }
+               else {
+                       *dst++ = *src;
+               }
+       }
+       dst->opcode = BIND_OPCODE_DONE;
+       
+       // optimize phase 3, use immediate encodings
+       for (binding_tmp* p = &mid[0]; p->opcode != REBASE_OPCODE_DONE; ++p) {
+               if ( (p->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB) 
+                       && (p->operand1 < (15*sizeof(pint_t)))
+                       && ((p->operand1 % sizeof(pint_t)) == 0) ) {
+                       p->opcode = BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED;
+                       p->operand1 = p->operand1/sizeof(pint_t);
+               }
+       }       
+       dst->opcode = BIND_OPCODE_DONE;
+
+
+       // convert to compressed encoding
+       const static bool log = false;
+       this->_encodedData.reserve(info.size()*2);
+       bool done = false;
+       for (typename std::vector<binding_tmp>::iterator it = mid.begin(); !done && it != mid.end() ; ++it) {
+               switch ( it->opcode ) {
+                       case BIND_OPCODE_DONE:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_DONE()\n");
+                               this->_encodedData.append_byte(BIND_OPCODE_DONE);
+                               done = true;
+                               break;
+                       case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%lld)\n", it->operand1);
+                               this->_encodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | it->operand1);
+                               break;
+                       case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%lld)\n", it->operand1);
+                               this->_encodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
+                               this->_encodedData.append_uleb128(it->operand1);
+                               break;
+                       case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%lld)\n", it->operand1);
+                               this->_encodedData.append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | (it->operand1 & BIND_IMMEDIATE_MASK));
+                               break;
+                       case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%0llX, %s)\n", it->operand1, it->name);
+                               this->_encodedData.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | it->operand1);
+                               this->_encodedData.append_string(it->name);
+                               break;
+                       case BIND_OPCODE_SET_TYPE_IMM:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_SET_TYPE_IMM(%lld)\n", it->operand1);
+                               this->_encodedData.append_byte(BIND_OPCODE_SET_TYPE_IMM | it->operand1);
+                               break;
+                       case BIND_OPCODE_SET_ADDEND_SLEB:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", it->operand1);
+                               this->_encodedData.append_byte(BIND_OPCODE_SET_ADDEND_SLEB);
+                               this->_encodedData.append_sleb128(it->operand1);
+                               break;
+                       case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%lld, 0x%llX)\n", it->operand1, it->operand2);
+                               this->_encodedData.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | it->operand1);
+                               this->_encodedData.append_uleb128(it->operand2);
+                               break;
+                       case BIND_OPCODE_ADD_ADDR_ULEB:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
+                               this->_encodedData.append_byte(BIND_OPCODE_ADD_ADDR_ULEB);
+                               this->_encodedData.append_uleb128(it->operand1);
+                               break;
+                       case BIND_OPCODE_DO_BIND:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND()\n");
+                               this->_encodedData.append_byte(BIND_OPCODE_DO_BIND);
+                               break;
+                       case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
+                               this->_encodedData.append_byte(BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB);
+                               this->_encodedData.append_uleb128(it->operand1);
+                               break;
+                       case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(%lld=0x%llX)\n", it->operand1, it->operand1*sizeof(pint_t));
+                               this->_encodedData.append_byte(BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED | it->operand1 );
+                               break;
+                       case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%lld, %lld)\n", it->operand1, it->operand2);
+                               this->_encodedData.append_byte(BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB);
+                               this->_encodedData.append_uleb128(it->operand1);
+                               this->_encodedData.append_uleb128(it->operand2);
+                               break;
+               }
+       }
+       
+       // align to pointer size
+       this->_encodedData.pad_to_size(sizeof(pint_t));
+
+       this->_encoded = true;
+
+       if (log) fprintf(stderr, "total weak binding info size = %ld\n", this->_encodedData.size());
+       
+}
+
+
+
+template <typename A>
+class LazyBindingInfoAtom : public LinkEditAtom
+{
+public:
+                                                                                               LazyBindingInfoAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+                                                                                                       : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) {_encoded = true;  }
+
+       // overrides of ld::Atom
+       virtual const char*                                                     name() const            { return "lazy binding 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 LazyBindingInfoAtom<A>::_s_section("__LINKEDIT", "__lazy_binding", ld::Section::typeLinkEdit, true);
+
+
+
+template <typename A>
+void LazyBindingInfoAtom<A>::encode() const
+{
+       // stream all lazy bindings and record start offsets
+       std::vector<OutputFile::BindingInfo>& info = this->_writer._lazyBindingInfo;
+       for (std::vector<OutputFile::BindingInfo>::const_iterator it = info.begin(); it != info.end(); ++it) {
+               // record start offset for use by stub helper
+               this->_writer.setLazyBindingInfoOffset(it->_address, this->_encodedData.size());
+
+               // write address to bind
+               uint64_t segStart = 0;
+               uint64_t segEnd = 0;
+               uint32_t segIndex = 0;  
+               if ( ! this->_writer.findSegment(this->_state, it->_address, &segStart, &segEnd, &segIndex) )
+                       throw "lazy binding address outside range of any segment";
+               this->_encodedData.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segIndex);
+               this->_encodedData.append_uleb128(it->_address - segStart);
+               
+               // write ordinal
+               if ( it->_libraryOrdinal <= 0 ) {
+                       // special lookups are encoded as negative numbers in BindingInfo
+                       this->_encodedData.append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | (it->_libraryOrdinal & BIND_IMMEDIATE_MASK) );
+               }
+               else if ( it->_libraryOrdinal <= 15 ) {
+                       // small ordinals are encoded in opcode
+                       this->_encodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | it->_libraryOrdinal);
+               }
+               else {
+                       this->_encodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
+                       this->_encodedData.append_uleb128(it->_libraryOrdinal);
+               }
+               // write symbol name
+               this->_encodedData.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | it->_flags);
+               this->_encodedData.append_string(it->_symbolName);
+               // write do bind
+               this->_encodedData.append_byte(BIND_OPCODE_DO_BIND);
+               this->_encodedData.append_byte(BIND_OPCODE_DONE);
+       }
+       
+       // align to pointer size
+       this->_encodedData.pad_to_size(sizeof(pint_t));
+       
+       this->_encoded = true;
+       //fprintf(stderr, "lazy binding info size = %ld, for %ld entries\n", _encodedData.size(), allLazys.size());
+}
+
+
+
+template <typename A>
+class ExportInfoAtom : public LinkEditAtom
+{
+public:
+                                                                                               ExportInfoAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+                                                                                                       : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { _encoded = true; }
+
+       // overrides of ld::Atom
+       virtual const char*                                                     name() const            { return "export 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;
+
+       const ld::Atom*                                                         stubForResolverFunction(const ld::Atom* resolver) const;
+
+       struct TrieEntriesSorter
+       {
+               TrieEntriesSorter(const Options& o) : _options(o) {}
+               
+                bool operator()(const mach_o::trie::Entry& left, const mach_o::trie::Entry& right)
+                {
+                       unsigned int leftOrder;
+                       unsigned int rightOrder;
+                       _options.exportedSymbolOrder(left.name, &leftOrder);
+                       _options.exportedSymbolOrder(right.name, &rightOrder);
+                       if ( leftOrder != rightOrder ) 
+                               return (leftOrder < rightOrder);
+                       else
+                               return (left.address < right.address);
+                }
+       private:
+               const Options&  _options;
+       };
+       
+       static ld::Section                      _s_section;
+};
+
+template <typename A>
+ld::Section ExportInfoAtom<A>::_s_section("__LINKEDIT", "__export", ld::Section::typeLinkEdit, true);
+
+template <typename A>
+const ld::Atom* ExportInfoAtom<A>::stubForResolverFunction(const ld::Atom* resolver) const
+{
+       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::typeStub) || (sect->type() == ld::Section::typeStubClose) ) {
+                       for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+                               const ld::Atom* atom = *ait;
+                               if ( strcmp(atom->name(), resolver->name()) == 0 )
+                                       return atom;
+                       }
+               }
+       }
+       assert(0 && "no stub for resolver function");
+       return NULL;
+}
+
+
+template <typename A>
+void ExportInfoAtom<A>::encode() const
+{
+       // make vector of mach_o::trie::Entry for all exported symbols
+       std::vector<const ld::Atom*>& exports = this->_writer._exportedAtoms;
+       uint64_t imageBaseAddress = this->_writer.headerAndLoadCommandsSection->address;
+       std::vector<mach_o::trie::Entry> entries;
+       entries.reserve(exports.size());
+       for (std::vector<const ld::Atom*>::const_iterator it = exports.begin(); it != exports.end(); ++it) {
+               const ld::Atom* atom = *it;
+               mach_o::trie::Entry entry;
+               uint64_t flags = (atom->contentType() == ld::Atom::typeTLV) ? EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL : EXPORT_SYMBOL_FLAGS_KIND_REGULAR;
+               uint64_t other = 0;
+               uint64_t address = atom->finalAddress() - imageBaseAddress;
+               if ( (atom->definition() == ld::Atom::definitionRegular) && (atom->combine() == ld::Atom::combineByName) )
+                       flags |= EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION;
+               if ( atom->definition() == ld::Atom::definitionProxy ) {
+                       entry.name = atom->name();
+                       entry.flags = flags | EXPORT_SYMBOL_FLAGS_REEXPORT;
+                       entry.other = this->_writer.compressedOrdinalForAtom(atom);
+                       if ( entry.other == BIND_SPECIAL_DYLIB_SELF ) {
+                               warning("not adding explict export for symbol %s because it is already re-exported from dylib %s", entry.name, atom->file()->path());
+                               continue;
+                       }
+                       if ( atom->isAlias() ) {
+                               // alias proxy means symbol was re-exported with a name change
+                               const ld::Atom* aliasOf = NULL;
+                               for (ld::Fixup::iterator fit = atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
+                                       if ( fit->kind == ld::Fixup::kindNoneFollowOn ) {
+                                               assert(fit->binding == ld::Fixup::bindingDirectlyBound);
+                                               aliasOf = fit->u.target;
+                                       }
+                               }
+                               assert(aliasOf != NULL);
+                               entry.importName = aliasOf->name();
+                       }
+                       else {
+                               // symbol name stays same as re-export
+                               entry.importName = atom->name();
+                       }
+                       entries.push_back(entry);
+                       //fprintf(stderr, "re-export %s from lib %llu as %s\n", entry.importName, entry.other, entry.name);
+               }
+               else {
+                       if ( atom->isThumb() )
+                               address |= 1;
+                       if ( atom->contentType() == ld::Atom::typeResolver ) {
+                               flags |= EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER;
+                               // set normal lookup to return stub address
+                               // and add resolver function in new location that newer dyld's can access
+                               other = address;
+                               const ld::Atom* stub = stubForResolverFunction(atom);
+                               address = stub->finalAddress() - imageBaseAddress;
+                               if ( stub->isThumb() )
+                                       address |= 1;
+                       }
+                       entry.name = atom->name();
+                       entry.flags = flags;
+                       entry.address = address; 
+                       entry.other = other; 
+                       entry.importName = NULL;
+                       entries.push_back(entry);
+               }
+       }
+
+       // sort vector by -exported_symbols_order, and any others by address
+       std::sort(entries.begin(), entries.end(), TrieEntriesSorter(_options));
+       
+       // create trie
+       mach_o::trie::makeTrie(entries, this->_encodedData.bytes());
+
+       // align to pointer size
+       this->_encodedData.pad_to_size(sizeof(pint_t));
+       
+       this->_encoded = true;
+}
+
+
+template <typename A>
+class SplitSegInfoAtom : public LinkEditAtom
+{
+public:
+                                                                                               SplitSegInfoAtom(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 "split seg 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;
+
+       void                                                                            addSplitSegInfo(uint64_t address, ld::Fixup::Kind k) const;
+       void                                                                            uleb128EncodeAddresses(const std::vector<uint64_t>& locations) const;
+
+       mutable std::vector<uint64_t>                           _32bitPointerLocations;
+       mutable std::vector<uint64_t>                           _64bitPointerLocations;
+       mutable std::vector<uint64_t>                           _ppcHi16Locations;
+
+
+       static ld::Section                      _s_section;
+};
+
+template <typename A>
+ld::Section SplitSegInfoAtom<A>::_s_section("__LINKEDIT", "__splitSegInfo", ld::Section::typeLinkEdit, true);
+
+template <>
+void SplitSegInfoAtom<x86_64>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind) const
+{
+       switch (kind) {
+               case ld::Fixup::kindStoreX86PCRel32:
+               case ld::Fixup::kindStoreX86PCRel32_1:
+               case ld::Fixup::kindStoreX86PCRel32_2:
+               case ld::Fixup::kindStoreX86PCRel32_4:
+               case ld::Fixup::kindStoreX86PCRel32GOTLoad:
+               case ld::Fixup::kindStoreX86PCRel32GOTLoadNowLEA:
+               case ld::Fixup::kindStoreX86PCRel32GOT:
+               case ld::Fixup::kindStoreLittleEndian32:
+               case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+               case ld::Fixup::kindStoreTargetAddressX86PCRel32:
+               case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
+               case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
+                       _32bitPointerLocations.push_back(address);
+                       break;
+               case ld::Fixup::kindStoreLittleEndian64:
+               case ld::Fixup::kindStoreTargetAddressLittleEndian64:
+                       _64bitPointerLocations.push_back(address);
+                       break;
+               default:
+                       warning("codegen at address 0x%08llX prevents image from working in dyld shared cache", address);
+                       break;
+       }
+}
+
+template <>
+void SplitSegInfoAtom<x86>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind) const
+{
+       switch (kind) {
+               case ld::Fixup::kindStoreLittleEndian32:
+               case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+                       _32bitPointerLocations.push_back(address);
+                       break;
+               default:
+                       warning("codegen at address 0x%08llX prevents image from working in dyld shared cache", address);
+                       break;
+       }
+}
+
+template <>
+void SplitSegInfoAtom<arm>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind) const
+{
+       switch (kind) {
+               case ld::Fixup::kindStoreLittleEndian32:
+                       _32bitPointerLocations.push_back(address);
+                       break;
+               default:
+                       warning("codegen at address 0x%08llX prevents image from working in dyld shared cache", address);
+                       break;
+       }
+}
+
+
+template <>
+void SplitSegInfoAtom<ppc>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind) const
+{
+       switch (kind) {
+               case ld::Fixup::kindStorePPCPicHigh16AddLow:
+                       _ppcHi16Locations.push_back(address);
+                       break;
+               case ld::Fixup::kindStoreBigEndian32:
+                       _32bitPointerLocations.push_back(address);
+                       break;
+               default:
+                       warning("codegen at address 0x%08llX prevents image from working in dyld shared cache", address);
+                       break;
+       }
+}
+
+
+template <>
+void SplitSegInfoAtom<ppc64>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind) const
+{
+       switch (kind) {
+               case ld::Fixup::kindStorePPCPicHigh16AddLow:
+                       _ppcHi16Locations.push_back(address);
+                       break;
+               default:
+                       warning("codegen at address 0x%08llX prevents image from working in dyld shared cache", address);
+                       break;
+       }
+}
+
+
+template <typename A>
+void SplitSegInfoAtom<A>::uleb128EncodeAddresses(const std::vector<uint64_t>& locations) const
+{
+       pint_t addr = this->_options.baseAddress();
+       for(typename std::vector<uint64_t>::const_iterator it = locations.begin(); it != locations.end(); ++it) {
+               pint_t nextAddr = *it;
+               //fprintf(stderr, "nextAddr=0x%0llX\n", (uint64_t)nextAddr);
+               uint64_t delta = nextAddr - addr;
+               //fprintf(stderr, "delta=0x%0llX\n", delta);
+               if ( delta == 0 ) 
+                       throw "double split seg info for same address";
+               // uleb128 encode
+               uint8_t byte;
+               do {
+                       byte = delta & 0x7F;
+                       delta &= ~0x7F;
+                       if ( delta != 0 )
+                               byte |= 0x80;
+                       this->_encodedData.append_byte(byte);
+                       delta = delta >> 7;
+               } 
+               while( byte >= 0x80 );
+               addr = nextAddr;
+       }
+}
+
+
+template <typename A>
+void SplitSegInfoAtom<A>::encode() const
+{
+       // sort into group by pointer adjustment kind
+       std::vector<OutputFile::SplitSegInfoEntry>& info = this->_writer._splitSegInfos;
+       for (std::vector<OutputFile::SplitSegInfoEntry>::const_iterator it = info.begin(); it != info.end(); ++it) {
+               this->addSplitSegInfo(it->address, it->kind);
+       }
+
+       // delta compress runs of addresses
+       this->_encodedData.reserve(8192);
+       if ( _32bitPointerLocations.size() != 0 ) {
+               this->_encodedData.append_byte(1);
+               //fprintf(stderr, "type 1:\n");
+               std::sort(_32bitPointerLocations.begin(), _32bitPointerLocations.end());
+               this->uleb128EncodeAddresses(_32bitPointerLocations);
+               this->_encodedData.append_byte(0); // terminator
+       }
+       
+       if ( _64bitPointerLocations.size() != 0 ) {
+               this->_encodedData.append_byte(2);
+               //fprintf(stderr, "type 2:\n");
+               std::sort(_64bitPointerLocations.begin(), _64bitPointerLocations.end());
+               this->uleb128EncodeAddresses(_64bitPointerLocations);
+               this->_encodedData.append_byte(0); // terminator
+       }
+
+       if ( _ppcHi16Locations.size() != 0 ) {
+               this->_encodedData.append_byte(3);
+               //fprintf(stderr, "type 3:\n");
+               std::sort(_ppcHi16Locations.begin(), _ppcHi16Locations.end());
+               this->uleb128EncodeAddresses(_ppcHi16Locations);
+               this->_encodedData.append_byte(0); // terminator
+       }
+
+       // always add zero byte to mark end
+       this->_encodedData.append_byte(0);
+
+       // align to pointer size
+       this->_encodedData.pad_to_size(sizeof(pint_t));
+       
+       this->_encoded = true;
+       
+       // clean up temporaries
+       _32bitPointerLocations.clear();
+       _64bitPointerLocations.clear();
+       _ppcHi16Locations.clear();
+}
+
+
+template <typename A>
+class FunctionStartsAtom : public LinkEditAtom
+{
+public:
+                                                                                               FunctionStartsAtom(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 "function starts"; }
+       // 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 FunctionStartsAtom<A>::_s_section("__LINKEDIT", "__funcStarts", ld::Section::typeLinkEdit, true);
+
+
+template <typename A>
+void FunctionStartsAtom<A>::encode() const
+{
+       this->_encodedData.reserve(8192);
+       const uint64_t badAddress = 1;
+       uint64_t addr = badAddress;
+       // delta compress all function addresses
+       for (std::vector<ld::Internal::FinalSection*>::iterator it = this->_state.sections.begin(); it != this->_state.sections.end(); ++it) {
+               ld::Internal::FinalSection* sect = *it;
+               if ( sect->type() == ld::Section::typeMachHeader ) {
+                       // start with delta from start of __TEXT
+                       addr = sect->address;
+               }
+               else if ( sect->type() == ld::Section::typeCode ) {
+                       assert(addr != badAddress);
+                       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;
+                               uint64_t nextAddr = atom->finalAddress();
+                               if ( atom->isThumb() )
+                                       nextAddr |= 1; 
+                               uint64_t delta = nextAddr - addr;
+                               if ( delta != 0 )
+                                       this->_encodedData.append_uleb128(delta);
+                               addr = nextAddr;
+                       }
+               }
+       }
+       
+       // terminator
+       this->_encodedData.append_byte(0); 
+       
+       // align to pointer size
+       this->_encodedData.pad_to_size(sizeof(pint_t));         
+
+       this->_encoded = true;
+}
+
+
+
+} // namespace tool 
+} // namespace ld 
+
+#endif // __LINKEDIT_HPP__
diff --git a/src/ld/LinkEditClassic.hpp b/src/ld/LinkEditClassic.hpp
new file mode 100644 (file)
index 0000000..d5438ac
--- /dev/null
@@ -0,0 +1,2542 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
+ *
+ * Copyright (c) 2009-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@
+ */
+
+#ifndef __LINKEDIT_CLASSIC_HPP__
+#define __LINKEDIT_CLASSIC_HPP__
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+
+#include <vector>
+
+#include "Options.h"
+#include "ld.hpp"
+#include "Architectures.hpp"
+#include "MachOFileAbstraction.hpp"
+
+namespace ld {
+namespace tool {
+
+
+
+class ClassicLinkEditAtom : public ld::Atom
+{
+public:
+
+       // overrides of ld::Atom
+       virtual ld::File*                                                       file() const            { return NULL; }
+       virtual bool                                                            translationUnitSource(const char** dir, const char** nm) const
+                                                                                                                                       { return false; }
+       virtual uint64_t                                                        objectAddress() const { return 0; }
+
+       virtual void                                                            encode() = 0;
+       virtual bool                                                            hasStabs(uint32_t& ssos, uint32_t& ssoe, uint32_t& sos, uint32_t& soe) { return false; }
+
+                                                                                               ClassicLinkEditAtom(const Options& opts, ld::Internal& state, 
+                                                                                                                               OutputFile& writer, const ld::Section& sect,
+                                                                                                                               unsigned int pointerSize)
+                                                                                               : ld::Atom(sect, ld::Atom::definitionRegular,
+                                                                                                                       ld::Atom::combineNever, ld::Atom::scopeTranslationUnit,
+                                                                                                                       ld::Atom::typeUnclassified, ld::Atom::symbolTableNotIn,
+                                                                                                                       false, false, false, ld::Atom::Alignment(log2(pointerSize))), 
+                                                                                                               _options(opts), _state(state), _writer(writer) { }
+protected:     
+       const Options&                          _options;
+       ld::Internal&                           _state;
+       OutputFile&                                     _writer;
+};
+
+
+
+class StringPoolAtom : public ClassicLinkEditAtom
+{
+public:
+                                                                                               StringPoolAtom(const Options& opts, ld::Internal& state, 
+                                                                                                                               OutputFile& writer, int pointerSize);
+
+       // overrides of ld::Atom
+       virtual const char*                                                     name() const            { return "string pool"; }
+       virtual uint64_t                                                        size() const;
+       virtual void                                                            copyRawContent(uint8_t buffer[]) const; 
+       // overrides of ClassicLinkEditAtom
+       virtual void                                                            encode() { }
+
+       int32_t                                                                         add(const char* name);
+       int32_t                                                                         addUnique(const char* name);
+       int32_t                                                                         emptyString()                   { return 1; }
+       const char*                                                                     stringForIndex(int32_t) const;
+       uint32_t                                                                        currentOffset();
+
+private:
+       class CStringEquals
+       {
+       public:
+               bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+       };
+       enum { kBufferSize = 0x01000000 };
+       typedef __gnu_cxx::hash_map<const char*, int32_t, __gnu_cxx::hash<const char*>, CStringEquals> StringToOffset;
+
+       const uint32_t                                                  _pointerSize;
+       std::vector<char*>                                              _fullBuffers;
+       char*                                                                   _currentBuffer;
+       uint32_t                                                                _currentBufferUsed;
+       StringToOffset                                                  _uniqueStrings;
+
+       static ld::Section                      _s_section;
+};
+
+ld::Section StringPoolAtom::_s_section("__LINKEDIT", "__string_pool", ld::Section::typeLinkEdit, true);
+
+
+StringPoolAtom::StringPoolAtom(const Options& opts, ld::Internal& state, OutputFile& writer, int pointerSize)
+       : ClassicLinkEditAtom(opts, state, writer, _s_section, pointerSize), 
+        _pointerSize(pointerSize), _currentBuffer(NULL), _currentBufferUsed(0)
+{
+       _currentBuffer = new char[kBufferSize];
+       // burn first byte of string pool (so zero is never a valid string offset)
+       _currentBuffer[_currentBufferUsed++] = ' ';
+       // make offset 1 always point to an empty string
+       _currentBuffer[_currentBufferUsed++] = '\0';
+}
+
+uint64_t StringPoolAtom::size() const
+{
+       // pointer size align size
+       return (kBufferSize * _fullBuffers.size() + _currentBufferUsed + _pointerSize-1) & (-_pointerSize);
+}
+
+void StringPoolAtom::copyRawContent(uint8_t buffer[]) const
+{
+       uint64_t offset = 0;
+       for (unsigned int i=0; i < _fullBuffers.size(); ++i) {
+               memcpy(&buffer[offset], _fullBuffers[i], kBufferSize);
+               offset += kBufferSize;
+       }
+       memcpy(&buffer[offset], _currentBuffer, _currentBufferUsed);
+       // zero fill end to align
+       offset += _currentBufferUsed;
+       while ( (offset % _pointerSize) != 0 )
+               buffer[offset++] = 0;
+}
+
+int32_t StringPoolAtom::add(const char* str)
+{
+       int32_t offset = kBufferSize * _fullBuffers.size() + _currentBufferUsed;
+       int lenNeeded = strlcpy(&_currentBuffer[_currentBufferUsed], str, kBufferSize-_currentBufferUsed)+1;
+       if ( (_currentBufferUsed+lenNeeded) < kBufferSize ) {
+               _currentBufferUsed += lenNeeded;
+       }
+       else {
+               int copied = kBufferSize-_currentBufferUsed-1;
+               // change trailing '\0' that strlcpy added to real char
+               _currentBuffer[kBufferSize-1] = str[copied];
+               // alloc next buffer
+               _fullBuffers.push_back(_currentBuffer);
+               _currentBuffer = new char[kBufferSize];
+               _currentBufferUsed = 0;
+               // append rest of string
+               this->add(&str[copied+1]);
+       }
+       return offset;
+}
+
+uint32_t StringPoolAtom::currentOffset()
+{
+       return kBufferSize * _fullBuffers.size() + _currentBufferUsed;
+}
+
+
+int32_t StringPoolAtom::addUnique(const char* str)
+{
+       StringToOffset::iterator pos = _uniqueStrings.find(str);
+       if ( pos != _uniqueStrings.end() ) {
+               return pos->second;
+       }
+       else {
+               int32_t offset = this->add(str);
+               _uniqueStrings[str] = offset;
+               return offset;
+       }
+}
+
+
+const char* StringPoolAtom::stringForIndex(int32_t index) const
+{
+       int32_t currentBufferStartIndex = kBufferSize * _fullBuffers.size();
+       int32_t maxIndex = currentBufferStartIndex + _currentBufferUsed;
+       // check for out of bounds
+       if ( index > maxIndex )
+               return "";
+       // check for index in _currentBuffer
+       if ( index > currentBufferStartIndex )
+               return &_currentBuffer[index-currentBufferStartIndex];
+       // otherwise index is in a full buffer
+       uint32_t fullBufferIndex = index/kBufferSize;
+       return &_fullBuffers[fullBufferIndex][index-(kBufferSize*fullBufferIndex)];
+}
+
+
+
+template <typename A>
+class SymbolTableAtom : public ClassicLinkEditAtom
+{
+public:
+                                                                                               SymbolTableAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+                                                                                                       : ClassicLinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)),
+                                                                                                               _stabsStringsOffsetStart(0), _stabsStringsOffsetEnd(0),
+                                                                                                               _stabsIndexStart(0), _stabsIndexEnd(0) { }
+
+       // overrides of ld::Atom
+       virtual const char*                                                     name() const            { return "symbol table"; }
+       virtual uint64_t                                                        size() const;
+       virtual void                                                            copyRawContent(uint8_t buffer[]) const; 
+       // overrides of ClassicLinkEditAtom
+       virtual void                                                            encode();
+       virtual bool                                                            hasStabs(uint32_t& ssos, uint32_t& ssoe, uint32_t& sos, uint32_t& soe);
+
+private:
+       typedef typename A::P                                           P;
+       typedef typename A::P::E                                        E;
+       typedef typename A::P::uint_t                           pint_t;
+
+       bool                                                    addLocal(const ld::Atom* atom, StringPoolAtom* pool);
+       void                                                    addGlobal(const ld::Atom* atom, StringPoolAtom* pool);
+       void                                                    addImport(const ld::Atom* atom, StringPoolAtom* pool);
+       uint8_t                                                 classicOrdinalForProxy(const ld::Atom* atom);
+       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);
+       
+
+       mutable std::vector<macho_nlist<P> >    _globals;
+       mutable std::vector<macho_nlist<P> >    _locals;
+       mutable std::vector<macho_nlist<P> >    _imports;
+       
+       uint32_t                                                                _stabsStringsOffsetStart;
+       uint32_t                                                                _stabsStringsOffsetEnd;
+       uint32_t                                                                _stabsIndexStart;
+       uint32_t                                                                _stabsIndexEnd;
+
+       static ld::Section                      _s_section;
+};
+
+template <typename A>
+ld::Section SymbolTableAtom<A>::_s_section("__LINKEDIT", "__symbol_table", ld::Section::typeLinkEdit, true);
+
+
+
+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
+       const char* symbolName = atom->name();
+       char anonName[32];
+       if ( this->_options.outputKind() == Options::kObjectFile ) {
+               if ( atom->contentType() == ld::Atom::typeCString ) {
+                       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++);
+                               symbolName = anonName;
+                       }
+               }
+               else if ( atom->contentType() == ld::Atom::typeCFI ) {
+                       if ( _options.removeEHLabels() )
+                               return false;
+                       // synthesize .eh name
+                       if ( strcmp(atom->name(), "CIE") == 0 )
+                               symbolName = "EH_Frame1";
+                       else
+                               symbolName = "func.eh";
+               }
+               else 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
+       uint8_t type = N_SECT;
+       if ( atom->definition() == ld::Atom::definitionAbsolute ) {
+               type = N_ABS;
+       }
+       else if ( (atom->section().type() == ld::Section::typeObjC1Classes) 
+                               && (this->_options.outputKind() == Options::kObjectFile) ) {
+               // __OBJC __class has floating abs symbols for each class data structure
+               type = N_ABS;
+       }
+       if ( atom->scope() == ld::Atom::scopeLinkageUnit )
+               type |= N_PEXT;
+       entry.set_n_type(type);
+
+       // set n_sect (section number of implementation )
+       if ( atom->definition() == ld::Atom::definitionAbsolute )
+               entry.set_n_sect(0);
+       else
+               entry.set_n_sect(atom->machoSection());
+
+       // set n_desc
+       uint16_t desc = 0;
+    if ( atom->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip )
+        desc |= REFERENCED_DYNAMICALLY;
+    if ( atom->dontDeadStrip() && (this->_options.outputKind() == Options::kObjectFile) )
+        desc |= N_NO_DEAD_STRIP;
+       if ( (atom->definition() == ld::Atom::definitionRegular) && (atom->combine() == ld::Atom::combineByName) )
+               desc |= N_WEAK_DEF;
+       if ( atom->isThumb() )
+               desc |= N_ARM_THUMB_DEF;
+       entry.set_n_desc(desc);
+
+       // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
+       if ( atom->definition() == ld::Atom::definitionAbsolute ) 
+               entry.set_n_value(atom->objectAddress());
+       else
+               entry.set_n_value(atom->finalAddress());
+       
+       // add to array
+       _locals.push_back(entry);
+       return true;
+}
+
+
+template <typename A>
+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()));
+
+       // set n_type
+       if ( atom->definition() == ld::Atom::definitionAbsolute ) {
+               entry.set_n_type(N_EXT | N_ABS);
+       }
+       else if ( (atom->section().type() == ld::Section::typeObjC1Classes)
+                               && (this->_options.outputKind() == Options::kObjectFile) ) {
+               // __OBJC __class has floating abs symbols for each class data structure
+               entry.set_n_type(N_EXT | N_ABS);
+       }
+       else if ( (atom->definition() == ld::Atom::definitionProxy) && (atom->scope() == ld::Atom::scopeGlobal) ) {
+               entry.set_n_type(N_EXT | N_INDR);
+       }
+       else {
+               entry.set_n_type(N_EXT | N_SECT);
+               if ( (atom->scope() == ld::Atom::scopeLinkageUnit) && (this->_options.outputKind() == Options::kObjectFile) ) {
+                       if ( this->_options.keepPrivateExterns() )
+                               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
+                       entry.set_n_type(N_EXT | N_ABS);
+               }
+       }
+
+       // set n_sect (section number of implementation)
+       if ( atom->definition() == ld::Atom::definitionAbsolute )
+               entry.set_n_sect(0);
+       else if ( (atom->definition() == ld::Atom::definitionProxy) && (atom->scope() == ld::Atom::scopeGlobal) )
+               entry.set_n_sect(0); 
+       else
+               entry.set_n_sect(atom->machoSection());
+
+       // set n_desc
+       uint16_t desc = 0;
+    if ( atom->isThumb() )
+        desc |= N_ARM_THUMB_DEF;
+    if ( atom->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip )
+        desc |= REFERENCED_DYNAMICALLY;
+    if ( (atom->contentType() == ld::Atom::typeResolver) && (this->_options.outputKind() == Options::kObjectFile) )
+        desc |= N_SYMBOL_RESOLVER;
+    if ( atom->dontDeadStrip() && (this->_options.outputKind() == Options::kObjectFile) )
+        desc |= N_NO_DEAD_STRIP;
+       if ( (atom->definition() == ld::Atom::definitionRegular) && (atom->combine() == ld::Atom::combineByName) ) {
+               desc |= N_WEAK_DEF;
+               // <rdar://problem/6783167> support auto hidden weak symbols: .weak_def_can_be_hidden
+               if ( (atom->scope() == ld::Atom::scopeGlobal) && atom->autoHide() && (this->_options.outputKind() == Options::kObjectFile) ) 
+                       desc |= N_WEAK_REF;
+       }
+       entry.set_n_desc(desc);
+
+       // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
+       if ( atom->definition() == ld::Atom::definitionAbsolute ) 
+               entry.set_n_value(atom->objectAddress());
+       else if ( (atom->definition() == ld::Atom::definitionProxy) && (atom->scope() == ld::Atom::scopeGlobal) ) {
+               if ( atom->isAlias() ) {
+                       // this re-export also renames
+                       for (ld::Fixup::iterator fit = atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
+                               if ( fit->kind == ld::Fixup::kindNoneFollowOn ) {
+                                       assert(fit->binding == ld::Fixup::bindingDirectlyBound);
+                                       entry.set_n_value(pool->add(fit->u.target->name()));
+                               }
+                       }
+               }
+               else
+                       entry.set_n_value(entry.n_strx());
+       }
+       else
+               entry.set_n_value(atom->finalAddress());
+               
+       // add to array
+       _globals.push_back(entry);
+}
+
+template <typename A>
+uint8_t        SymbolTableAtom<A>::classicOrdinalForProxy(const ld::Atom* atom)
+{
+       assert(atom->definition() == ld::Atom::definitionProxy);
+       // when linking for flat-namespace ordinals are always zero 
+       if ( _options.nameSpace() != Options::kTwoLevelNameSpace )
+               return 0;
+       const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(atom->file());
+       // when linking -undefined dynamic_lookup, unbound symbols use DYNAMIC_LOOKUP_ORDINAL
+       if ( dylib == NULL ) {
+               if (_options.undefinedTreatment() == Options::kUndefinedDynamicLookup )
+                       return DYNAMIC_LOOKUP_ORDINAL;
+               if (_options.allowedUndefined(atom->name()) )
+                       return DYNAMIC_LOOKUP_ORDINAL;
+       }
+       assert(dylib != NULL);
+       int ord = this->_writer.dylibToOrdinal(dylib);
+       if ( ord == BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE )
+               return EXECUTABLE_ORDINAL;
+       return ord;
+}
+
+
+template <typename A>
+void SymbolTableAtom<A>::addImport(const ld::Atom* atom, StringPoolAtom* pool) 
+{
+       macho_nlist<P> entry;
+
+       // set n_strx
+       entry.set_n_strx(pool->add(atom->name()));
+
+       // set n_type
+       if ( this->_options.outputKind() == Options::kObjectFile ) {
+               if ( (atom->scope() == ld::Atom::scopeLinkageUnit) 
+                               && (atom->definition() == ld::Atom::definitionTentative) )
+                       entry.set_n_type(N_UNDF | N_EXT | N_PEXT);
+               else 
+                       entry.set_n_type(N_UNDF | N_EXT);
+       }
+       else {
+               if ( this->_options.prebind() )
+                       entry.set_n_type(N_PBUD | N_EXT);
+               else 
+                       entry.set_n_type(N_UNDF | N_EXT);
+       }
+
+       // set n_sect
+       entry.set_n_sect(0);
+
+       uint16_t desc = 0;
+       if ( this->_options.outputKind() != Options::kObjectFile ) {
+               uint8_t ordinal = this->classicOrdinalForProxy(atom);
+               //fprintf(stderr, "ordinal=%u from reader=%p for symbol=%s\n", ordinal, atom->getFile(), atom->getName());
+               SET_LIBRARY_ORDINAL(desc, ordinal);
+               
+#if 0
+               // set n_desc ( high byte is library ordinal, low byte is reference type )
+               std::map<const ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fStubsMap.find(atom);
+               if ( pos != fStubsMap.end() || ( strncmp(atom->getName(), ".objc_class_name_", 17) == 0) )
+                       desc |= REFERENCE_FLAG_UNDEFINED_LAZY;
+               else
+                       desc |= REFERENCE_FLAG_UNDEFINED_NON_LAZY;
+#endif
+       }
+       else if ( atom->definition() == ld::Atom::definitionTentative ) {
+               uint8_t align = atom->alignment().powerOf2;
+               // always record custom alignment of common symbols to match what compiler does
+               SET_COMM_ALIGN(desc, align);
+       }
+       if ( (this->_options.outputKind() != Options::kObjectFile)
+               && (atom->definition() == ld::Atom::definitionProxy) 
+               && (atom->combine() == ld::Atom::combineByName) ) {
+                       desc |= N_REF_TO_WEAK;
+       }
+       if ( atom->weakImported() )     
+               desc |= N_WEAK_REF;
+       entry.set_n_desc(desc);
+
+       // set n_value, zero for import proxy and size for tentative definition
+       if ( atom->definition() == ld::Atom::definitionTentative )
+               entry.set_n_value(atom->size());
+       else
+               entry.set_n_value(0);
+       
+       // add to array
+       _imports.push_back(entry);
+}
+
+template <typename A>
+uint8_t SymbolTableAtom<A>::sectionIndexForStab(const ld::relocatable::File::Stab& stab)
+{
+       // in FUN stabs, n_sect field is 0 for start FUN and 1 for end FUN
+       if ( stab.type == N_FUN )
+               return stab.other;
+       else if ( stab.type == N_GSYM ) 
+               return 0;
+       else if ( stab.atom != NULL ) 
+               return stab.atom->machoSection();
+       else
+               return stab.other;
+}
+
+
+template <typename A>
+uint64_t SymbolTableAtom<A>::valueForStab(const ld::relocatable::File::Stab& stab)
+{
+       switch ( stab.type ) {
+               case N_FUN:
+                       if ( stab.atom == NULL ) {
+                               // <rdar://problem/5591394> Add support to ld64 for N_FUN stabs when used for symbolic constants
+                               return stab.value;
+                       }
+                       if ( (stab.string == NULL) || (strlen(stab.string) == 0) ) {
+                               // end of function N_FUN has size
+                               return stab.atom->size();
+                       }
+                       else {
+                               // start of function N_FUN has address
+                               return stab.atom->finalAddress();
+                       }
+               case N_LBRAC:
+               case N_RBRAC:
+               case N_SLINE:
+                       if ( stab.atom == NULL )
+                               // some weird assembly files have slines not associated with a function
+                               return stab.value;
+                       else
+                               // all these stab types need their value changed from an offset in the atom to an address
+                               return stab.atom->finalAddress() + stab.value;
+               case N_STSYM:
+               case N_LCSYM:
+               case N_BNSYM:
+                       // all these need address of atom
+                       if ( stab.atom != NULL )
+                               return stab.atom->finalAddress();
+                       else
+                               return 0;  // <rdar://problem/7811357> work around for mismatch N_BNSYM 
+               case N_ENSYM:
+                       return stab.atom->size();
+               case N_SO:
+                       if ( stab.atom == NULL ) {
+                               return 0;
+                       }
+                       else {
+                               if ( (stab.string == NULL) || (strlen(stab.string) == 0) ) {
+                                       // end of translation unit N_SO has address of end of last atom
+                                       return stab.atom->finalAddress() + stab.atom->size();
+                               }
+                               else {
+                                       // start of translation unit N_SO has address of end of first atom
+                                       return stab.atom->finalAddress();
+                               }
+                       }
+                       break;
+               default:
+                       return stab.value;
+       }
+}
+
+template <typename A>
+uint32_t SymbolTableAtom<A>::stringOffsetForStab(const ld::relocatable::File::Stab& stab, StringPoolAtom* pool)
+{
+       switch (stab.type) {
+               case N_SO:
+                       if ( (stab.string == NULL) || stab.string[0] == '\0' ) {
+                               return pool->emptyString();
+                               break;
+                       }
+                       // fall into uniquing case
+               case N_SOL:
+               case N_BINCL:
+               case N_EXCL:
+                       return pool->addUnique(stab.string);
+                       break;
+               default:
+                       if ( stab.string == NULL )
+                               return 0;
+                       else if ( stab.string[0] == '\0' )
+                               return pool->emptyString();
+                       else
+                               return pool->add(stab.string);
+       }
+       return 0;
+}
+
+
+
+template <typename A>
+bool SymbolTableAtom<A>::hasStabs(uint32_t& ssos, uint32_t& ssoe, uint32_t& sos, uint32_t& soe)
+{
+       ssos = _stabsStringsOffsetStart;
+       ssoe = _stabsStringsOffsetEnd;
+       sos = _stabsIndexStart * sizeof(macho_nlist<P>);
+       soe = _stabsIndexEnd * sizeof(macho_nlist<P>);
+       return ( (_stabsIndexStart != _stabsIndexEnd) || (_stabsStringsOffsetStart != _stabsStringsOffsetEnd) );
+}
+
+template <typename A>
+void SymbolTableAtom<A>::encode()
+{
+       uint32_t symbolIndex = 0;
+
+       // make nlist entries for all local symbols
+       std::vector<const ld::Atom*>& localAtoms = this->_writer._localAtoms;
+       _locals.reserve(localAtoms.size()+this->_state.stabs.size());
+       this->_writer._localSymbolsStartIndex = 0;
+       // make nlist entries for all debug notes
+       _stabsIndexStart = symbolIndex;
+       _stabsStringsOffsetStart = this->_writer._stringPoolAtom->currentOffset();
+       for (std::vector<ld::relocatable::File::Stab>::const_iterator sit=this->_state.stabs.begin(); sit != this->_state.stabs.end(); ++sit) {
+               macho_nlist<P> entry;
+               entry.set_n_type(sit->type);
+               entry.set_n_sect(sectionIndexForStab(*sit));
+               entry.set_n_desc(sit->desc);
+               entry.set_n_value(valueForStab(*sit));
+               entry.set_n_strx(stringOffsetForStab(*sit, this->_writer._stringPoolAtom));
+               _locals.push_back(entry);
+               ++symbolIndex;
+       }
+       _stabsIndexEnd = symbolIndex;
+       _stabsStringsOffsetEnd = this->_writer._stringPoolAtom->currentOffset();
+       for (std::vector<const ld::Atom*>::const_iterator it=localAtoms.begin(); it != localAtoms.end(); ++it) {
+               const ld::Atom* atom = *it;
+               if ( this->addLocal(atom, this->_writer._stringPoolAtom) )
+                       this->_writer._atomToSymbolIndex[atom] = 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) {
+               const ld::Atom* atom = *it;
+               this->addGlobal(atom, this->_writer._stringPoolAtom);
+               this->_writer._atomToSymbolIndex[atom] = symbolIndex++;
+       }
+       this->_writer._globalSymbolsCount = symbolIndex - this->_writer._globalSymbolsStartIndex;
+
+       // make nlist entries for all undefined (imported) symbols
+       std::vector<const ld::Atom*>& importAtoms = this->_writer._importedAtoms;
+       _imports.reserve(importAtoms.size());
+       this->_writer._importSymbolsStartIndex = symbolIndex;
+       for (std::vector<const ld::Atom*>::const_iterator it=importAtoms.begin(); it != importAtoms.end(); ++it) {
+               this->addImport(*it, this->_writer._stringPoolAtom);
+               this->_writer._atomToSymbolIndex[*it] = symbolIndex++;
+       }
+       this->_writer._importSymbolsCount = symbolIndex - this->_writer._importSymbolsStartIndex;
+}
+
+template <typename A>
+uint64_t SymbolTableAtom<A>::size() const
+{
+       return sizeof(macho_nlist<P>) * (_locals.size() + _globals.size() + _imports.size());
+}
+
+template <typename A>
+void SymbolTableAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+       memcpy(&buffer[this->_writer._localSymbolsStartIndex*sizeof(macho_nlist<P>)], &_locals[0], 
+                                                                                               this->_writer._localSymbolsCount*sizeof(macho_nlist<P>));
+       memcpy(&buffer[this->_writer._globalSymbolsStartIndex*sizeof(macho_nlist<P>)], &_globals[0],
+                                                                                               this->_writer._globalSymbolsCount*sizeof(macho_nlist<P>));
+       memcpy(&buffer[this->_writer._importSymbolsStartIndex *sizeof(macho_nlist<P>)], &_imports[0], 
+                                                                                               this->_writer._importSymbolsCount*sizeof(macho_nlist<P>));
+}
+
+
+
+
+class RelocationsAtomAbstract : public ClassicLinkEditAtom
+{
+public:
+                                                                                               RelocationsAtomAbstract(const Options& opts, ld::Internal& state, 
+                                                                                                                               OutputFile& writer, const ld::Section& sect,
+                                                                                                                               unsigned int pointerSize)
+                                                                                                       : ClassicLinkEditAtom(opts, state, writer, sect, pointerSize) { }
+
+       virtual void                                                    addPointerReloc(uint64_t addr, uint32_t symNum) = 0;
+       virtual void                                                    addTextReloc(uint64_t addr, ld::Fixup::Kind k, uint64_t targetAddr, uint32_t symNum) = 0;
+       virtual void                                                    addExternalPointerReloc(uint64_t addr, const ld::Atom*) = 0;
+       virtual void                                                    addExternalCallSiteReloc(uint64_t addr, const ld::Atom*) = 0;
+       virtual uint64_t                                                relocBaseAddress(ld::Internal& state) = 0;
+       virtual void                                                    addSectionReloc(ld::Internal::FinalSection*     sect, ld::Fixup::Kind, 
+                                                                                                                       const ld::Atom* inAtom, uint32_t offsetInAtom, 
+                                                                                                                       bool toTargetUsesExternalReloc ,bool fromTargetExternalReloc,
+                                                                                                                       const ld::Atom* toTarget, uint64_t toAddend, 
+                                                                                                                       const ld::Atom* fromTarget, uint64_t fromAddend) = 0;
+protected:
+       uint32_t                                                                symbolIndex(const ld::Atom* atom) const;
+
+};
+
+
+
+uint32_t RelocationsAtomAbstract::symbolIndex(const ld::Atom* atom) const
+{
+       std::map<const ld::Atom*, uint32_t>::iterator pos = this->_writer._atomToSymbolIndex.find(atom);
+       if ( pos != this->_writer._atomToSymbolIndex.end() )
+               return pos->second;
+       fprintf(stderr, "_atomToSymbolIndex content:\n");
+       for(std::map<const ld::Atom*, uint32_t>::iterator it = this->_writer._atomToSymbolIndex.begin(); it != this->_writer._atomToSymbolIndex.end(); ++it) {
+                       fprintf(stderr, "%p(%s) => %d\n", it->first, it->first->name(), it->second);
+       }
+       throwf("internal error: atom not found in symbolIndex(%s)", atom->name());
+}
+
+
+template <typename A>
+class LocalRelocationsAtom : public RelocationsAtomAbstract
+{
+public:
+                                                                                               LocalRelocationsAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+                                                                                                       : RelocationsAtomAbstract(opts, state, writer, _s_section, sizeof(pint_t)) { }
+
+       // overrides of ld::Atom
+       virtual const char*                                                     name() const            { return "local relocations"; }
+       virtual uint64_t                                                        size() const;
+       virtual void                                                            copyRawContent(uint8_t buffer[]) const; 
+       // overrides of ClassicLinkEditAtom
+       virtual void                                                            encode() {}
+       // overrides of RelocationsAtomAbstract
+       virtual void                                                            addPointerReloc(uint64_t addr, uint32_t symNum);
+       virtual void                                                            addExternalPointerReloc(uint64_t addr, const ld::Atom*) {}
+       virtual void                                                            addExternalCallSiteReloc(uint64_t addr, const ld::Atom*) {}
+       virtual uint64_t                                                        relocBaseAddress(ld::Internal& state);
+       virtual void                                                            addTextReloc(uint64_t addr, ld::Fixup::Kind k, uint64_t targetAddr, uint32_t symNum);
+       virtual void                                                            addSectionReloc(ld::Internal::FinalSection*     sect, ld::Fixup::Kind, 
+                                                                                                                       const ld::Atom* inAtom, uint32_t offsetInAtom, 
+                                                                                                                       bool toTargetUsesExternalReloc ,bool fromTargetExternalReloc,
+                                                                                                                       const ld::Atom* toTarget, uint64_t toAddend, 
+                                                                                                                       const ld::Atom* fromTarget, uint64_t fromAddend) { }
+
+private:
+       typedef typename A::P                                           P;
+       typedef typename A::P::E                                        E;
+       typedef typename A::P::uint_t                           pint_t;
+       
+       std::vector<macho_relocation_info<P> >          _relocs;
+
+       static ld::Section                      _s_section;
+};
+
+template <typename A>
+ld::Section LocalRelocationsAtom<A>::_s_section("__LINKEDIT", "__local_relocs", ld::Section::typeLinkEdit, true);
+
+
+template <>
+uint64_t LocalRelocationsAtom<x86_64>::relocBaseAddress(ld::Internal& state)
+{
+       if ( _options.outputKind() == Options::kKextBundle ) {
+               // for kext bundles the reloc base address starts at __TEXT segment
+               return _options.baseAddress();
+       }
+       // for all other kinds, the x86_64 reloc base address starts at __DATA segment
+       for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+               ld::Internal::FinalSection* sect = *sit;
+               if ( strcmp(sect->segmentName(), "__DATA") == 0 )
+                       return sect->address;
+       }
+       throw "__DATA segment not found";
+}
+
+template <typename A>
+uint64_t LocalRelocationsAtom<A>::relocBaseAddress(ld::Internal& state)
+{
+       return _options.baseAddress();
+}
+
+template <typename A>
+void LocalRelocationsAtom<A>::addPointerReloc(uint64_t addr, uint32_t symNum)
+{
+       macho_relocation_info<P> reloc;
+       reloc.set_r_address(addr);
+       reloc.set_r_symbolnum(symNum);
+       reloc.set_r_pcrel(false);
+       reloc.set_r_length();
+       reloc.set_r_extern(false);
+       reloc.set_r_type(GENERIC_RELOC_VANILLA);
+       _relocs.push_back(reloc);
+}
+
+template <typename A>
+void LocalRelocationsAtom<A>::addTextReloc(uint64_t addr, ld::Fixup::Kind kind, uint64_t targetAddr, uint32_t symNum)
+{
+       macho_relocation_info<P> reloc1;
+       macho_relocation_info<P> reloc2;
+       switch ( kind ) {
+               case ld::Fixup::kindStorePPCAbsLow14:
+               case ld::Fixup::kindStorePPCAbsLow16:
+                       // a reference to the absolute address of something in this same linkage unit can be 
+                       // encoded as a local text reloc in a dylib or bundle 
+                       if ( _options.outputSlidable() ) {
+                               reloc1.set_r_address(addr);
+                               reloc1.set_r_symbolnum(symNum);
+                               reloc1.set_r_pcrel(false);
+                               reloc1.set_r_length(2);
+                               reloc1.set_r_extern(false);
+                               reloc1.set_r_type(kind==ld::Fixup::kindStorePPCAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
+                               reloc2.set_r_address(targetAddr >> 16);
+                               reloc2.set_r_symbolnum(0);
+                               reloc2.set_r_pcrel(false);
+                               reloc2.set_r_length(2);
+                               reloc2.set_r_extern(false);
+                               reloc2.set_r_type(PPC_RELOC_PAIR);
+                               _relocs.push_back(reloc1);
+                               _relocs.push_back(reloc2);
+                       }
+                       break;
+               case ld::Fixup::kindStorePPCAbsHigh16AddLow:
+               case ld::Fixup::kindStorePPCAbsHigh16:
+                       if ( _options.outputSlidable() ) {
+                               reloc1.set_r_address(addr);
+                               reloc1.set_r_symbolnum(symNum);
+                               reloc1.set_r_pcrel(false);
+                               reloc1.set_r_length(2);
+                               reloc1.set_r_extern(false);
+                               reloc1.set_r_type(kind==ld::Fixup::kindStorePPCAbsHigh16AddLow ? PPC_RELOC_HA16 : PPC_RELOC_HI16);
+                               reloc2.set_r_address(targetAddr & 0xFFFF);
+                               reloc2.set_r_symbolnum(0);
+                               reloc2.set_r_pcrel(false);
+                               reloc2.set_r_length(2);
+                               reloc2.set_r_extern(false);
+                               reloc2.set_r_type(PPC_RELOC_PAIR);
+                               _relocs.push_back(reloc1);
+                               _relocs.push_back(reloc2);
+                       }
+                       break;
+               default:
+                       break;
+       }
+}
+
+
+template <typename A>
+uint64_t LocalRelocationsAtom<A>::size() const
+{
+       return _relocs.size() * sizeof(macho_relocation_info<P>);
+}
+
+template <typename A>
+void LocalRelocationsAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+       memcpy(buffer, &_relocs[0], _relocs.size()*sizeof(macho_relocation_info<P>));
+}
+
+
+
+
+
+
+template <typename A>
+class ExternalRelocationsAtom : public RelocationsAtomAbstract
+{
+public:
+                                                                                               ExternalRelocationsAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+                                                                                                       : RelocationsAtomAbstract(opts, state, writer, _s_section, sizeof(pint_t)) { }
+
+       // overrides of ld::Atom
+       virtual const char*                                                     name() const            { return "external relocations"; }
+       virtual uint64_t                                                        size() const;
+       virtual void                                                            copyRawContent(uint8_t buffer[]) const; 
+       // overrides of ClassicLinkEditAtom
+       virtual void                                                            encode() {}
+       // overrides of RelocationsAtomAbstract
+       virtual void                                                            addPointerReloc(uint64_t addr, uint32_t symNum) {}
+       virtual void                                                            addTextReloc(uint64_t addr, ld::Fixup::Kind k, uint64_t targetAddr, uint32_t symNum) {}
+       virtual void                                                            addExternalPointerReloc(uint64_t addr, const ld::Atom*);
+       virtual void                                                            addExternalCallSiteReloc(uint64_t addr, const ld::Atom*);
+       virtual uint64_t                                                        relocBaseAddress(ld::Internal& state);
+       virtual void                                                            addSectionReloc(ld::Internal::FinalSection*     sect, ld::Fixup::Kind, 
+                                                                                                                       const ld::Atom* inAtom, uint32_t offsetInAtom, 
+                                                                                                                       bool toTargetUsesExternalReloc ,bool fromTargetExternalReloc,
+                                                                                                                       const ld::Atom* toTarget, uint64_t toAddend, 
+                                                                                                                       const ld::Atom* fromTarget, uint64_t fromAddend) { }
+       
+
+private:
+       typedef typename A::P                                           P;
+       typedef typename A::P::E                                        E;
+       typedef typename A::P::uint_t                           pint_t;
+       
+       struct LocAndAtom { 
+                                                       LocAndAtom(uint64_t l, const ld::Atom* a) : loc(l), atom(a), symbolIndex(0) {}
+
+               uint64_t                        loc; 
+               const ld::Atom*         atom; 
+               uint32_t                        symbolIndex;
+               
+               bool operator<(const LocAndAtom& rhs) const {
+                       // sort first by symbol number
+                       if ( this->symbolIndex != rhs.symbolIndex )
+                               return (this->symbolIndex < rhs.symbolIndex);
+                       // then sort all uses of the same symbol by address
+                       return (this->loc < rhs.loc);
+               }
+               
+       };
+
+       static uint32_t         pointerReloc();
+       static uint32_t         callReloc();
+
+       mutable std::vector<LocAndAtom>                 _pointerLocations;
+       mutable std::vector<LocAndAtom>                 _callSiteLocations;
+
+       static ld::Section                      _s_section;
+};
+
+template <typename A>
+ld::Section ExternalRelocationsAtom<A>::_s_section("__LINKEDIT", "__extrn_relocs", ld::Section::typeLinkEdit, true);
+
+template <>
+uint64_t ExternalRelocationsAtom<x86_64>::relocBaseAddress(ld::Internal& state)
+{
+       // for x86_64 the reloc base address starts at __DATA segment
+       for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+               ld::Internal::FinalSection* sect = *sit;
+               if ( strcmp(sect->segmentName(), "__DATA") == 0 )
+                       return sect->address;
+       }
+       throw "__DATA segment not found";
+}
+
+template <typename A>
+uint64_t ExternalRelocationsAtom<A>::relocBaseAddress(ld::Internal& state)
+{
+       return 0;
+}
+
+template <typename A>
+void ExternalRelocationsAtom<A>::addExternalPointerReloc(uint64_t addr, const ld::Atom* target)
+{
+       _pointerLocations.push_back(LocAndAtom(addr, target));
+}
+
+template <typename A>
+void ExternalRelocationsAtom<A>::addExternalCallSiteReloc(uint64_t addr, const ld::Atom* target)
+{
+       _callSiteLocations.push_back(LocAndAtom(addr, target));
+}
+
+
+template <typename A>
+uint64_t ExternalRelocationsAtom<A>::size() const
+{
+       if ( _options.outputKind() == Options::kStaticExecutable ) {
+               assert(_pointerLocations.size() == 0);
+               assert(_callSiteLocations.size() == 0);
+       }
+       return (_pointerLocations.size() + _callSiteLocations.size()) * sizeof(macho_relocation_info<P>);
+}
+
+template <> uint32_t ExternalRelocationsAtom<arm>::pointerReloc() { return ARM_RELOC_VANILLA; }
+template <> uint32_t ExternalRelocationsAtom<x86>::pointerReloc() { return GENERIC_RELOC_VANILLA; }
+template <> uint32_t ExternalRelocationsAtom<ppc>::pointerReloc() { return PPC_RELOC_VANILLA; }
+template <> uint32_t ExternalRelocationsAtom<x86_64>::pointerReloc() { return X86_64_RELOC_UNSIGNED; }
+template <> uint32_t ExternalRelocationsAtom<ppc64>::pointerReloc() { return PPC_RELOC_VANILLA; }
+
+
+template <> uint32_t ExternalRelocationsAtom<x86_64>::callReloc() { return X86_64_RELOC_BRANCH; }
+template <> uint32_t ExternalRelocationsAtom<x86>::callReloc() { return GENERIC_RELOC_VANILLA; }
+template <typename A> 
+uint32_t ExternalRelocationsAtom<A>::callReloc() 
+{ 
+       assert(0 && "external call relocs not implemented");
+       return 0; 
+}
+
+
+template <typename A>
+void ExternalRelocationsAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+       macho_relocation_info<P>* r = (macho_relocation_info<P>*)buffer;
+       
+       // assign symbol index, now that symbol table is built
+       for (typename std::vector<LocAndAtom>::iterator it = _pointerLocations.begin(); it != _pointerLocations.end(); ++it) {
+               it->symbolIndex = symbolIndex(it->atom);
+       }
+       std::sort(_pointerLocations.begin(), _pointerLocations.end());
+       for (typename std::vector<LocAndAtom>::const_iterator it = _pointerLocations.begin(); it != _pointerLocations.end(); ++it, ++r) {
+               r->set_r_address(it->loc);
+               r->set_r_symbolnum(it->symbolIndex);
+               r->set_r_pcrel(false);
+               r->set_r_length();
+               r->set_r_extern(true);
+               r->set_r_type(this->pointerReloc());
+       }
+       
+       for (typename std::vector<LocAndAtom>::iterator it = _callSiteLocations.begin(); it != _callSiteLocations.end(); ++it) {
+               it->symbolIndex = symbolIndex(it->atom);
+       }
+       std::sort(_callSiteLocations.begin(), _callSiteLocations.end());
+       for (typename std::vector<LocAndAtom>::const_iterator it = _callSiteLocations.begin(); it != _callSiteLocations.end(); ++it, ++r) {
+               r->set_r_address(it->loc);
+               r->set_r_symbolnum(it->symbolIndex);
+               r->set_r_pcrel(true);
+               r->set_r_length(2);
+               r->set_r_extern(true);
+               r->set_r_type(this->callReloc());
+       }
+}
+
+
+template <typename A>
+class SectionRelocationsAtom : public RelocationsAtomAbstract
+{
+public:
+                                                                                               SectionRelocationsAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+                                                                                                       : RelocationsAtomAbstract(opts, state, writer, _s_section, sizeof(pint_t)) { }
+
+       // overrides of ld::Atom
+       virtual const char*                                                     name() const            { return "section relocations"; }
+       virtual uint64_t                                                        size() const;
+       virtual void                                                            copyRawContent(uint8_t buffer[]) const; 
+       // overrides of ClassicLinkEditAtom
+       virtual void                                                            encode();
+       // overrides of RelocationsAtomAbstract
+       virtual void                                                            addPointerReloc(uint64_t addr, uint32_t symNum) {}
+       virtual void                                                            addTextReloc(uint64_t addr, ld::Fixup::Kind k, uint64_t targetAddr, uint32_t symNum) {}
+       virtual void                                                            addExternalPointerReloc(uint64_t addr, const ld::Atom*) {}
+       virtual void                                                            addExternalCallSiteReloc(uint64_t addr, const ld::Atom*) {}
+       virtual uint64_t                                                        relocBaseAddress(ld::Internal& state) { return 0; }
+       virtual void                                                            addSectionReloc(ld::Internal::FinalSection*     sect, ld::Fixup::Kind, 
+                                                                                                                       const ld::Atom* inAtom, uint32_t offsetInAtom, 
+                                                                                                                       bool toTargetUsesExternalReloc ,bool fromTargetExternalReloc,
+                                                                                                                       const ld::Atom* toTarget, uint64_t toAddend, 
+                                                                                                                       const ld::Atom* fromTarget, uint64_t fromAddend);
+               
+private:
+       typedef typename A::P                                           P;
+       typedef typename A::P::E                                        E;
+       typedef typename A::P::uint_t                           pint_t;
+       
+
+       struct Entry {
+               ld::Fixup::Kind                         kind;
+               bool                                            toTargetUsesExternalReloc;
+               bool                                            fromTargetUsesExternalReloc;
+               const ld::Atom*                         inAtom;
+               uint32_t                                        offsetInAtom;
+               const ld::Atom*                         toTarget; 
+               uint64_t                                        toAddend; 
+               const ld::Atom*                         fromTarget; 
+               uint64_t                                        fromAddend;
+       };
+       uint32_t                                                                        sectSymNum(bool external, const ld::Atom* target);
+       void                                                                            encodeSectionReloc(ld::Internal::FinalSection* sect, 
+                                                                                                                               const Entry& entry, std::vector<macho_relocation_info<P> >& relocs);
+       
+       struct SectionAndEntries {
+               ld::Internal::FinalSection*                             sect;
+               std::vector<Entry>                                              entries;
+               std::vector<macho_relocation_info<P> >  relocs;
+       };
+       
+       std::vector<SectionAndEntries>                          _entriesBySection;
+
+       static ld::Section                                                      _s_section;
+};
+
+template <typename A>
+ld::Section SectionRelocationsAtom<A>::_s_section("__LINKEDIT", "__sect_relocs", ld::Section::typeLinkEdit, true);
+
+
+
+
+template <typename A>
+uint64_t SectionRelocationsAtom<A>::size() const
+{
+       uint32_t count = 0;
+       for(typename std::vector<SectionAndEntries>::const_iterator it=_entriesBySection.begin(); it != _entriesBySection.end(); ++it) {
+               const SectionAndEntries& se = *it;
+               count += se.relocs.size();
+       }
+       return count * sizeof(macho_relocation_info<P>);
+}
+
+template <typename A>
+void SectionRelocationsAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+       uint32_t offset = 0;
+       for(typename std::vector<SectionAndEntries>::const_iterator it=_entriesBySection.begin(); it != _entriesBySection.end(); ++it) {
+               const SectionAndEntries& se = *it;
+               memcpy(&buffer[offset], &se.relocs[0], se.relocs.size()*sizeof(macho_relocation_info<P>));
+               offset += (se.relocs.size() * sizeof(macho_relocation_info<P>));
+       }
+}
+
+
+template <>
+void SectionRelocationsAtom<x86_64>::encodeSectionReloc(ld::Internal::FinalSection* sect, 
+                                                                                                       const Entry& entry, std::vector<macho_relocation_info<P> >& relocs)
+{
+       macho_relocation_info<P> reloc1;
+       macho_relocation_info<P> reloc2;
+       uint64_t address = entry.inAtom->finalAddress()+entry.offsetInAtom - sect->address;
+       bool external = entry.toTargetUsesExternalReloc;
+       uint32_t symbolNum = sectSymNum(external, entry.toTarget);
+       bool fromExternal = false;
+       uint32_t fromSymbolNum = 0;
+       if ( entry.fromTarget != NULL ) {
+               fromExternal = entry.fromTargetUsesExternalReloc;
+               fromSymbolNum = sectSymNum(fromExternal, entry.fromTarget);
+       }
+       
+       
+       switch ( entry.kind ) {
+               case ld::Fixup::kindStoreX86BranchPCRel32:
+               case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
+               case ld::Fixup::kindStoreX86DtraceCallSiteNop:
+               case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolNum);
+                       reloc1.set_r_pcrel(true);
+                       reloc1.set_r_length(2);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(X86_64_RELOC_BRANCH);
+                       relocs.push_back(reloc1);
+                       break;
+                       
+               case ld::Fixup::kindStoreX86BranchPCRel8:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolNum);
+                       reloc1.set_r_pcrel(true);
+                       reloc1.set_r_length(0);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(X86_64_RELOC_BRANCH);
+                       relocs.push_back(reloc1);
+                       break;
+                       
+               case ld::Fixup::kindStoreX86PCRel32:
+               case ld::Fixup::kindStoreTargetAddressX86PCRel32:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolNum);
+                       reloc1.set_r_pcrel(true);
+                       reloc1.set_r_length(2);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(X86_64_RELOC_SIGNED);
+                       relocs.push_back(reloc1);
+                       break;
+                       
+               case ld::Fixup::kindStoreX86PCRel32_1:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolNum);
+                       reloc1.set_r_pcrel(true);
+                       reloc1.set_r_length(2);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(X86_64_RELOC_SIGNED_1);
+                       relocs.push_back(reloc1);
+                       break;
+                       
+               case ld::Fixup::kindStoreX86PCRel32_2:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolNum);
+                       reloc1.set_r_pcrel(true);
+                       reloc1.set_r_length(2);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(X86_64_RELOC_SIGNED_2);
+                       relocs.push_back(reloc1);
+                       break;
+                       
+               case ld::Fixup::kindStoreX86PCRel32_4:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolNum);
+                       reloc1.set_r_pcrel(true);
+                       reloc1.set_r_length(2);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(X86_64_RELOC_SIGNED_4);
+                       relocs.push_back(reloc1);
+                       break;
+               
+               case ld::Fixup::kindStoreX86PCRel32GOTLoad:
+               case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolNum);
+                       reloc1.set_r_pcrel(true);
+                       reloc1.set_r_length(2);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(X86_64_RELOC_GOT_LOAD);
+                       relocs.push_back(reloc1);
+                       break;
+
+               case ld::Fixup::kindStoreX86PCRel32GOT:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolNum);
+                       reloc1.set_r_pcrel(true);
+                       reloc1.set_r_length(2);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(X86_64_RELOC_GOT);
+                       relocs.push_back(reloc1);
+                       break;
+
+               case ld::Fixup::kindStoreLittleEndian64:
+               case ld::Fixup::kindStoreTargetAddressLittleEndian64:
+                       if ( entry.fromTarget != NULL ) {
+                               // this is a pointer-diff
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(false);
+                               reloc1.set_r_length(3);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
+                               reloc2.set_r_address(address);
+                               reloc2.set_r_symbolnum(fromSymbolNum);
+                               reloc2.set_r_pcrel(false);
+                               reloc2.set_r_length(3);
+                               reloc2.set_r_extern(fromExternal);
+                               reloc2.set_r_type(X86_64_RELOC_SUBTRACTOR);
+                               relocs.push_back(reloc2);
+                               relocs.push_back(reloc1);
+                       }
+                       else {
+                               // regular pointer
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(false);
+                               reloc1.set_r_length(3);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
+                               relocs.push_back(reloc1);
+                       }
+                       break;
+
+               case ld::Fixup::kindStoreLittleEndian32:
+               case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+                       if ( entry.fromTarget != NULL ) {
+                               // this is a pointer-diff
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(false);
+                               reloc1.set_r_length(2);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
+                               reloc2.set_r_address(address);
+                               reloc2.set_r_symbolnum(fromSymbolNum);
+                               reloc2.set_r_pcrel(false);
+                               reloc2.set_r_length(2);
+                               reloc2.set_r_extern(fromExternal);
+                               reloc2.set_r_type(X86_64_RELOC_SUBTRACTOR);
+                               relocs.push_back(reloc2);
+                               relocs.push_back(reloc1);
+                       }
+                       else {
+                               // regular pointer
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(false);
+                               reloc1.set_r_length(2);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
+                               relocs.push_back(reloc1);
+                       }
+                       break;
+               default:
+                       assert(0 && "need to handle -r reloc");
+               
+       }
+
+}
+
+
+
+template <typename A>
+uint32_t SectionRelocationsAtom<A>::sectSymNum(bool external, const ld::Atom* target)
+{
+       if ( target->definition() == ld::Atom::definitionAbsolute ) 
+               return R_ABS;
+       if ( external )
+               return this->symbolIndex(target);       // in external relocations, r_symbolnum field is symbol index
+       else
+               return target->machoSection();          // in non-extern relocations, r_symbolnum is mach-o section index of target
+}
+
+template <>
+void SectionRelocationsAtom<x86>::encodeSectionReloc(ld::Internal::FinalSection* sect, 
+                                                                                                       const Entry& entry, std::vector<macho_relocation_info<P> >& relocs)
+{
+       macho_relocation_info<P> reloc1;
+       macho_relocation_info<P> reloc2;
+       macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
+       macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
+       uint64_t address = entry.inAtom->finalAddress()+entry.offsetInAtom - sect->address;
+       bool external = entry.toTargetUsesExternalReloc;
+       uint32_t symbolNum = sectSymNum(external, entry.toTarget);
+       bool fromExternal = false;
+       uint32_t fromSymbolNum = 0;
+       if ( entry.fromTarget != NULL ) {
+               fromExternal = entry.fromTargetUsesExternalReloc;
+               fromSymbolNum = sectSymNum(fromExternal, entry.fromTarget);
+       }
+       
+       
+       switch ( entry.kind ) {
+               case ld::Fixup::kindStoreX86PCRel32:
+               case ld::Fixup::kindStoreX86BranchPCRel32:
+               case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
+               case ld::Fixup::kindStoreX86DtraceCallSiteNop:
+               case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
+                       if ( !external && (entry.toAddend != 0) ) {
+                               // use scattered reloc is target offset is non-zero
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(true);
+                               sreloc1->set_r_length(2);
+                               sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
+                               sreloc1->set_r_address(address);
+                               sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       }
+                       else {
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(true);
+                               reloc1.set_r_length(2);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(GENERIC_RELOC_VANILLA);
+                       }
+                       relocs.push_back(reloc1);
+                       break;
+       
+               case ld::Fixup::kindStoreX86BranchPCRel8:
+                       if ( !external && (entry.toAddend != 0) ) {
+                               // use scattered reloc is target offset is non-zero
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(true);
+                               sreloc1->set_r_length(0);
+                               sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
+                               sreloc1->set_r_address(address);
+                               sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       }
+                       else {
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(true);
+                               reloc1.set_r_length(0);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(GENERIC_RELOC_VANILLA);
+                       }
+                       relocs.push_back(reloc1);
+                       break;
+
+               case ld::Fixup::kindStoreX86PCRel16:
+                       if ( !external && (entry.toAddend != 0) ) {
+                               // use scattered reloc is target offset is non-zero
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(true);
+                               sreloc1->set_r_length(1);
+                               sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
+                               sreloc1->set_r_address(address);
+                               sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       }
+                       else {
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(true);
+                               reloc1.set_r_length(1);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(GENERIC_RELOC_VANILLA);
+                       }
+                       relocs.push_back(reloc1);
+                       break;
+
+               case ld::Fixup::kindStoreLittleEndian32:
+               case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+                       if ( entry.fromTarget != NULL ) {
+                               // this is a pointer-diff
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(false);
+                               sreloc1->set_r_length(2);
+                               if ( entry.toTarget->scope() == ld::Atom::scopeTranslationUnit )
+                                       sreloc1->set_r_type(GENERIC_RELOC_LOCAL_SECTDIFF);
+                               else
+                                       sreloc1->set_r_type(GENERIC_RELOC_SECTDIFF);
+                               sreloc1->set_r_address(address);
+                               if ( entry.toTarget == entry.inAtom )
+                                       sreloc1->set_r_value(entry.toTarget->finalAddress()+entry.toAddend);
+                               else
+                                       sreloc1->set_r_value(entry.toTarget->finalAddress());
+                               sreloc2->set_r_scattered(true);
+                               sreloc2->set_r_pcrel(false);
+                               sreloc2->set_r_length(2);
+                               sreloc2->set_r_type(GENERIC_RELOC_PAIR);
+                               sreloc2->set_r_address(0);
+                               if ( entry.fromTarget == entry.inAtom ) {
+                                       if ( entry.fromAddend > entry.fromTarget->size() )
+                                               sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.offsetInAtom);
+                                       else
+                                               sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.fromAddend);
+                               }
+                               else
+                                       sreloc2->set_r_value(entry.fromTarget->finalAddress());
+                               relocs.push_back(reloc1);
+                               relocs.push_back(reloc2);
+                       }
+                       else {
+                               // regular pointer
+                               if ( !external && (entry.toAddend != 0) ) {
+                                       // use scattered reloc is target offset is non-zero
+                                       sreloc1->set_r_scattered(true);
+                                       sreloc1->set_r_pcrel(false);
+                                       sreloc1->set_r_length(2);
+                                       sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
+                                       sreloc1->set_r_address(address);
+                                       sreloc1->set_r_value(entry.toTarget->finalAddress());
+                               }
+                               else {
+                                       reloc1.set_r_address(address);
+                                       reloc1.set_r_symbolnum(symbolNum);
+                                       reloc1.set_r_pcrel(false);
+                                       reloc1.set_r_length(2);
+                                       reloc1.set_r_extern(external);
+                                       reloc1.set_r_type(GENERIC_RELOC_VANILLA);
+                               }
+                               relocs.push_back(reloc1);
+                       }
+                       break;
+               default:
+                       assert(0 && "need to handle -r reloc");
+               
+       }
+}
+
+
+template <>
+void SectionRelocationsAtom<arm>::encodeSectionReloc(ld::Internal::FinalSection* sect, 
+                                                                                                       const Entry& entry, std::vector<macho_relocation_info<P> >& relocs)
+{
+       macho_relocation_info<P> reloc1;
+       macho_relocation_info<P> reloc2;
+       macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
+       macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
+       uint64_t address = entry.inAtom->finalAddress()+entry.offsetInAtom - sect->address;
+       bool external = entry.toTargetUsesExternalReloc;
+       uint32_t symbolNum = sectSymNum(external, entry.toTarget);
+       bool fromExternal = false;
+       uint32_t fromSymbolNum = 0;
+       if ( entry.fromTarget != NULL ) {
+               fromExternal = entry.fromTargetUsesExternalReloc;
+               fromSymbolNum = sectSymNum(fromExternal, entry.fromTarget);
+       }
+       
+
+       switch ( entry.kind ) {
+               case ld::Fixup::kindStoreTargetAddressARMBranch24:
+               case ld::Fixup::kindStoreARMBranch24:
+               case ld::Fixup::kindStoreARMDtraceCallSiteNop:
+               case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear:
+                       if ( !external && (entry.toAddend != 0) ) {
+                               // use scattered reloc is target offset is non-zero
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(true);
+                               sreloc1->set_r_length(2);
+                               sreloc1->set_r_type(ARM_RELOC_BR24);
+                               sreloc1->set_r_address(address);
+                               sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       }
+                       else {
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(true);
+                               reloc1.set_r_length(2);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(ARM_RELOC_BR24);
+                       }
+                       relocs.push_back(reloc1);
+                       break;
+       
+               case ld::Fixup::kindStoreTargetAddressThumbBranch22:
+               case ld::Fixup::kindStoreThumbBranch22:
+               case ld::Fixup::kindStoreThumbDtraceCallSiteNop:
+               case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
+                       if ( !external && (entry.toAddend != 0) ) {
+                               // use scattered reloc is target offset is non-zero
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(true);
+                               sreloc1->set_r_length(2);
+                               sreloc1->set_r_type(ARM_THUMB_RELOC_BR22);
+                               sreloc1->set_r_address(address);
+                               sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       }
+                       else {
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(true);
+                               reloc1.set_r_length(2);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(ARM_THUMB_RELOC_BR22);
+                       }
+                       relocs.push_back(reloc1);
+                       break;
+
+               case ld::Fixup::kindStoreLittleEndian32:
+               case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+                       if ( entry.fromTarget != NULL ) {
+                               // this is a pointer-diff
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(false);
+                               sreloc1->set_r_length(2);
+                               if ( entry.toTarget->scope() == ld::Atom::scopeTranslationUnit )
+                                       sreloc1->set_r_type(ARM_RELOC_LOCAL_SECTDIFF);
+                               else
+                                       sreloc1->set_r_type(ARM_RELOC_SECTDIFF);
+                               sreloc1->set_r_address(address);
+                               if ( entry.toTarget == entry.inAtom )
+                                       sreloc1->set_r_value(entry.toTarget->finalAddress()+entry.toAddend);
+                               else
+                                       sreloc1->set_r_value(entry.toTarget->finalAddress());
+                               sreloc2->set_r_scattered(true);
+                               sreloc2->set_r_pcrel(false);
+                               sreloc2->set_r_length(2);
+                               sreloc2->set_r_type(ARM_RELOC_PAIR);
+                               sreloc2->set_r_address(0);
+                               if ( entry.fromTarget == entry.inAtom ) {
+                                       //unsigned int pcBaseOffset = entry.inAtom->isThumb() ? 4 : 8;
+                                       //if ( entry.fromAddend > pcBaseOffset )
+                                       //      sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.fromAddend-pcBaseOffset);
+                                       //else
+                                               sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.fromAddend);
+                               }
+                               else {
+                                       sreloc2->set_r_value(entry.fromTarget->finalAddress());
+                               }
+                               relocs.push_back(reloc1);
+                               relocs.push_back(reloc2);
+                       }
+                       else {
+                               // regular pointer
+                               if ( !external && (entry.toAddend != 0) ) {
+                                       // use scattered reloc is target offset is non-zero
+                                       sreloc1->set_r_scattered(true);
+                                       sreloc1->set_r_pcrel(false);
+                                       sreloc1->set_r_length(2);
+                                       sreloc1->set_r_type(ARM_RELOC_VANILLA);
+                                       sreloc1->set_r_address(address);
+                                       sreloc1->set_r_value(entry.toTarget->finalAddress());
+                               }
+                               else {
+                                       reloc1.set_r_address(address);
+                                       reloc1.set_r_symbolnum(symbolNum);
+                                       reloc1.set_r_pcrel(false);
+                                       reloc1.set_r_length(2);
+                                       reloc1.set_r_extern(external);
+                                       reloc1.set_r_type(ARM_RELOC_VANILLA);
+                               }
+                               relocs.push_back(reloc1);
+                       }
+                       break;
+                       
+               case ld::Fixup::kindStoreARMLow16:
+               case ld::Fixup::kindStoreARMHigh16:
+               case ld::Fixup::kindStoreThumbLow16:
+               case ld::Fixup::kindStoreThumbHigh16:
+                       {
+                               int len = 0;
+                               uint32_t otherHalf = 0;
+                               uint32_t value = entry.toTarget->finalAddress()+entry.toAddend;
+                               if ( entry.fromTarget != NULL ) 
+                                       value -= (entry.fromTarget->finalAddress()+entry.fromAddend);
+                               switch ( entry.kind ) {
+                                       case ld::Fixup::kindStoreARMLow16:
+                                               len = 0;
+                                               otherHalf = value >> 16;
+                                               break;
+                                       case ld::Fixup::kindStoreARMHigh16:
+                                               len = 1;
+                                               otherHalf = value & 0xFFFF;
+                                               break;
+                                       case ld::Fixup::kindStoreThumbLow16:
+                                               len = 2;
+                                               otherHalf = value >> 16;
+                                               break;
+                                       case ld::Fixup::kindStoreThumbHigh16:
+                                               len = 3;
+                                               otherHalf = value & 0xFFFF;
+                                               break;
+                                       default:
+                                               break;
+                               }
+                               if ( entry.fromTarget != NULL ) {
+                                       // this is a sect-diff
+                                       sreloc1->set_r_scattered(true);
+                                       sreloc1->set_r_pcrel(false);
+                                       sreloc1->set_r_length(len);
+                                       sreloc1->set_r_type(ARM_RELOC_HALF_SECTDIFF);
+                                       sreloc1->set_r_address(address);
+                                       sreloc1->set_r_value(entry.toTarget->finalAddress());
+                                       sreloc2->set_r_scattered(true);
+                                       sreloc2->set_r_pcrel(false);
+                                       sreloc2->set_r_length(len);
+                                       sreloc2->set_r_type(ARM_RELOC_PAIR);
+                                       sreloc2->set_r_address(otherHalf);
+                                       if ( entry.fromTarget == entry.inAtom ) 
+                                               sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.fromAddend);
+                                       else 
+                                               sreloc2->set_r_value(entry.fromTarget->finalAddress());
+                                       relocs.push_back(reloc1);
+                                       relocs.push_back(reloc2);
+                               }
+                               else {
+                                       // this is absolute address
+                                       if ( !external && (entry.toAddend != 0) ) {
+                                               // use scattered reloc is target offset is non-zero
+                                               sreloc1->set_r_scattered(true);
+                                               sreloc1->set_r_pcrel(false);
+                                               sreloc1->set_r_length(len); 
+                                               sreloc1->set_r_type(ARM_RELOC_HALF);
+                                               sreloc1->set_r_address(address);
+                                               sreloc1->set_r_value(entry.toTarget->finalAddress());
+                                               reloc2.set_r_address(otherHalf);
+                                               reloc2.set_r_symbolnum(0);
+                                               reloc2.set_r_pcrel(false);
+                                               reloc2.set_r_length(len); 
+                                               reloc2.set_r_extern(false);
+                                               reloc2.set_r_type(ARM_RELOC_PAIR);
+                                               relocs.push_back(reloc1);
+                                               relocs.push_back(reloc2);
+                                       }
+                                       else {
+                                               reloc1.set_r_address(address);
+                                               reloc1.set_r_symbolnum(symbolNum);
+                                               reloc1.set_r_pcrel(false);
+                                               reloc1.set_r_length(len);
+                                               reloc1.set_r_extern(false);
+                                               reloc1.set_r_type(ARM_RELOC_HALF);
+                                               reloc2.set_r_address(otherHalf);  // other half
+                                               reloc2.set_r_symbolnum(0);
+                                               reloc2.set_r_pcrel(false);
+                                               reloc2.set_r_length(len); 
+                                               reloc2.set_r_extern(false);
+                                               reloc2.set_r_type(ARM_RELOC_PAIR);
+                                               relocs.push_back(reloc1);
+                                               relocs.push_back(reloc2);
+                                       }
+                               }
+                       }
+                       break;
+                                       
+               default:
+                       assert(0 && "need to handle -r reloc");
+               
+       }
+}
+
+
+template <>
+void SectionRelocationsAtom<ppc>::encodeSectionReloc(ld::Internal::FinalSection* sect, 
+                                                                                                       const Entry& entry, std::vector<macho_relocation_info<P> >& relocs)
+{
+       macho_relocation_info<P> reloc1;
+       macho_relocation_info<P> reloc2;
+       macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
+       macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
+       uint64_t address = entry.inAtom->finalAddress()+entry.offsetInAtom - sect->address;
+       bool external = entry.toTargetUsesExternalReloc;
+       uint32_t symbolNum = sectSymNum(external, entry.toTarget);
+       bool fromExternal = false;
+       uint32_t fromSymbolNum = 0;
+       if ( entry.fromTarget != NULL ) {
+               fromExternal = entry.fromTargetUsesExternalReloc;
+               fromSymbolNum= sectSymNum(fromExternal, entry.fromTarget);
+       }
+       uint32_t toAddr;
+       uint32_t fromAddr;
+       
+       switch ( entry.kind ) {
+       
+               case ld::Fixup::kindStorePPCBranch24:
+               case ld::Fixup::kindStoreTargetAddressPPCBranch24:
+               case ld::Fixup::kindStorePPCDtraceCallSiteNop:
+               case ld::Fixup::kindStorePPCDtraceIsEnableSiteClear:
+                       if ( !external && (entry.toAddend != 0) ) {
+                               // use scattered reloc if target offset is non-zero
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(true);
+                               sreloc1->set_r_length(2);
+                               sreloc1->set_r_type(PPC_RELOC_BR24);
+                               sreloc1->set_r_address(address);
+                               sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       }
+                       else {
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(true);
+                               reloc1.set_r_length(2);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(PPC_RELOC_BR24);
+                       }
+                       relocs.push_back(reloc1);
+                       break;
+
+               case ld::Fixup::kindStorePPCBranch14:
+                       if ( !external && (entry.toAddend != 0) ) {
+                               // use scattered reloc if target offset is non-zero
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(true);
+                               sreloc1->set_r_length(2);
+                               sreloc1->set_r_type(PPC_RELOC_BR14);
+                               sreloc1->set_r_address(address);
+                               sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       }
+                       else {
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(true);
+                               reloc1.set_r_length(2);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(PPC_RELOC_BR14);
+                       }
+                       relocs.push_back(reloc1);
+                       break;
+
+               case ld::Fixup::kindStoreBigEndian32:
+               case ld::Fixup::kindStoreTargetAddressBigEndian32:
+                       if ( entry.fromTarget != NULL ) {
+                               // this is a pointer-diff
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(false);
+                               sreloc1->set_r_length(2);
+                               if ( entry.toTarget->scope() == ld::Atom::scopeTranslationUnit )
+                                       sreloc1->set_r_type(PPC_RELOC_LOCAL_SECTDIFF);
+                               else
+                                       sreloc1->set_r_type(PPC_RELOC_SECTDIFF);
+                               sreloc1->set_r_address(address);
+                               if ( entry.toTarget == entry.inAtom )
+                                       sreloc1->set_r_value(entry.toTarget->finalAddress()+entry.toAddend);
+                               else
+                                       sreloc1->set_r_value(entry.toTarget->finalAddress());
+                               sreloc2->set_r_scattered(true);
+                               sreloc2->set_r_pcrel(false);
+                               sreloc2->set_r_length(2);
+                               sreloc2->set_r_type(PPC_RELOC_PAIR);
+                               sreloc2->set_r_address(0);
+                               if ( entry.fromTarget == entry.inAtom ) {
+                                       if ( entry.fromAddend > entry.fromTarget->size() )
+                                               sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.offsetInAtom);
+                                       else
+                                               sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.fromAddend);
+                               }
+                               else
+                                       sreloc2->set_r_value(entry.fromTarget->finalAddress());
+                               relocs.push_back(reloc1);
+                               relocs.push_back(reloc2);
+                       }
+                       else {
+                               // regular pointer
+                               if ( !external && (entry.toAddend != 0) ) {
+                                       // use scattered reloc is target offset is non-zero
+                                       sreloc1->set_r_scattered(true);
+                                       sreloc1->set_r_pcrel(false);
+                                       sreloc1->set_r_length(2);
+                                       sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
+                                       sreloc1->set_r_address(address);
+                                       sreloc1->set_r_value(entry.toTarget->finalAddress());
+                               }
+                               else {
+                                       reloc1.set_r_address(address);
+                                       reloc1.set_r_symbolnum(symbolNum);
+                                       reloc1.set_r_pcrel(false);
+                                       reloc1.set_r_length(2);
+                                       reloc1.set_r_extern(external);
+                                       reloc1.set_r_type(GENERIC_RELOC_VANILLA);
+                               }
+                               relocs.push_back(reloc1);
+                       }
+                       break;
+                       
+               case ld::Fixup::kindStorePPCAbsLow14:
+               case ld::Fixup::kindStorePPCAbsLow16:
+                       if ( !external && (entry.toAddend != 0) ) {
+                               // use scattered reloc if target offset is non-zero
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(false);
+                               sreloc1->set_r_length(2);
+                               sreloc1->set_r_type(entry.kind==ld::Fixup::kindStorePPCAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
+                               sreloc1->set_r_address(address);
+                               sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       }
+                       else {
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(false);
+                               reloc1.set_r_length(2);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(entry.kind==ld::Fixup::kindStorePPCAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
+                       }
+                       if ( external )
+                               reloc2.set_r_address(entry.toAddend >> 16);
+                       else
+                               reloc2.set_r_address((entry.toTarget->finalAddress()+entry.toAddend) >> 16);
+                       reloc2.set_r_symbolnum(0);
+                       reloc2.set_r_pcrel(false);
+                       reloc2.set_r_length(2);
+                       reloc2.set_r_extern(false);
+                       reloc2.set_r_type(PPC_RELOC_PAIR);
+                       relocs.push_back(reloc1);
+                       relocs.push_back(reloc2);
+                       break;
+                       
+               case ld::Fixup::kindStorePPCAbsHigh16:
+                       if ( !external && (entry.toAddend != 0) ) {
+                               // use scattered reloc if target offset is non-zero
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(false);
+                               sreloc1->set_r_length(2);
+                               sreloc1->set_r_type(PPC_RELOC_HI16);
+                               sreloc1->set_r_address(address);
+                               sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       }
+                       else {
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(false);
+                               reloc1.set_r_length(2);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(PPC_RELOC_HI16);
+                       }
+                       if ( external )
+                               reloc2.set_r_address(entry.toAddend & 0x0000FFFF);
+                       else
+                               reloc2.set_r_address((entry.toTarget->finalAddress()+entry.toAddend) & 0x0000FFFF);
+                       reloc2.set_r_symbolnum(0);
+                       reloc2.set_r_pcrel(false);
+                       reloc2.set_r_length(2);
+                       reloc2.set_r_extern(false);
+                       reloc2.set_r_type(PPC_RELOC_PAIR);
+                       relocs.push_back(reloc1);
+                       relocs.push_back(reloc2);
+                       break;
+                       
+               case ld::Fixup::kindStorePPCAbsHigh16AddLow:
+                       if ( !external && (entry.toAddend != 0) ) {
+                               // use scattered reloc if target offset is non-zero
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(false);
+                               sreloc1->set_r_length(2);
+                               sreloc1->set_r_type(PPC_RELOC_HA16);
+                               sreloc1->set_r_address(address);
+                               sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       }
+                       else {
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(false);
+                               reloc1.set_r_length(2);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(PPC_RELOC_HA16);
+                       }
+                       if ( external )
+                               reloc2.set_r_address(entry.toAddend & 0x0000FFFF);
+                       else
+                               reloc2.set_r_address((entry.toTarget->finalAddress()+entry.toAddend) & 0x0000FFFF);
+                       reloc2.set_r_symbolnum(0);
+                       reloc2.set_r_pcrel(false);
+                       reloc2.set_r_length(2);
+                       reloc2.set_r_extern(false);
+                       reloc2.set_r_type(PPC_RELOC_PAIR);
+                       relocs.push_back(reloc1);
+                       relocs.push_back(reloc2);
+                       break;
+                       
+               case ld::Fixup::kindStorePPCPicLow14:
+               case ld::Fixup::kindStorePPCPicLow16:
+                       fromAddr = entry.fromTarget->finalAddress() + entry.fromAddend;
+                       toAddr = entry.toTarget->finalAddress() + entry.toAddend;
+                       sreloc1->set_r_scattered(true);
+                       sreloc1->set_r_pcrel(false);
+                       sreloc1->set_r_length(2);
+                       sreloc1->set_r_type(entry.kind == ld::Fixup::kindStorePPCPicLow16 ? PPC_RELOC_LO16_SECTDIFF : PPC_RELOC_LO14_SECTDIFF);
+                       sreloc1->set_r_address(address);
+                       sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       sreloc2->set_r_scattered(true);
+                       sreloc2->set_r_pcrel(false);
+                       sreloc2->set_r_length(2);
+                       sreloc2->set_r_type(PPC_RELOC_PAIR);
+                       sreloc2->set_r_address(((toAddr-fromAddr) >> 16) & 0xFFFF);
+                       sreloc2->set_r_value(fromAddr);
+                       relocs.push_back(reloc1);
+                       relocs.push_back(reloc2);
+                       break;
+                       
+               case ld::Fixup::kindStorePPCPicHigh16AddLow:
+                       fromAddr = entry.fromTarget->finalAddress() + entry.fromAddend;
+                       toAddr = entry.toTarget->finalAddress() + entry.toAddend;
+                       sreloc1->set_r_scattered(true);
+                       sreloc1->set_r_pcrel(false);
+                       sreloc1->set_r_length(2);
+                       sreloc1->set_r_type(PPC_RELOC_HA16_SECTDIFF);
+                       sreloc1->set_r_address(address);
+                       sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       sreloc2->set_r_scattered(true);
+                       sreloc2->set_r_pcrel(false);
+                       sreloc2->set_r_length(2);
+                       sreloc2->set_r_type(PPC_RELOC_PAIR);
+                       sreloc2->set_r_address((toAddr-fromAddr) & 0xFFFF);
+                       sreloc2->set_r_value(fromAddr);
+                       relocs.push_back(reloc1);
+                       relocs.push_back(reloc2);
+                       break;
+                       
+               default:
+                       assert(0 && "need to handle -r reloc");
+               
+       }
+}
+
+template <>
+void SectionRelocationsAtom<ppc64>::encodeSectionReloc(ld::Internal::FinalSection* sect, 
+                                                                                                       const Entry& entry, std::vector<macho_relocation_info<P> >& relocs)
+{
+       macho_relocation_info<P> reloc1;
+       macho_relocation_info<P> reloc2;
+       macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
+       macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
+       uint64_t address = entry.inAtom->finalAddress()+entry.offsetInAtom - sect->address;
+       bool external = entry.toTargetUsesExternalReloc;
+       uint32_t symbolNum = sectSymNum(external, entry.toTarget);
+       bool fromExternal = false;
+       uint32_t fromSymbolNum = 0;
+       if ( entry.fromTarget != NULL ) {
+               fromExternal = entry.fromTargetUsesExternalReloc;
+               fromSymbolNum= sectSymNum(fromExternal, entry.fromTarget);
+       }
+       uint32_t toAddr;
+       uint32_t fromAddr;
+       
+       switch ( entry.kind ) {
+       
+               case ld::Fixup::kindStorePPCBranch24:
+               case ld::Fixup::kindStoreTargetAddressPPCBranch24:
+               case ld::Fixup::kindStorePPCDtraceCallSiteNop:
+               case ld::Fixup::kindStorePPCDtraceIsEnableSiteClear:
+                       if ( !external && (entry.toAddend != 0) ) {
+                               // use scattered reloc if target offset is non-zero
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(true);
+                               sreloc1->set_r_length(2);
+                               sreloc1->set_r_type(PPC_RELOC_BR24);
+                               sreloc1->set_r_address(address);
+                               sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       }
+                       else {
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(true);
+                               reloc1.set_r_length(2);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(PPC_RELOC_BR24);
+                       }
+                       relocs.push_back(reloc1);
+                       break;
+
+               case ld::Fixup::kindStorePPCBranch14:
+                       if ( !external && (entry.toAddend != 0) ) {
+                               // use scattered reloc if target offset is non-zero
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(true);
+                               sreloc1->set_r_length(2);
+                               sreloc1->set_r_type(PPC_RELOC_BR14);
+                               sreloc1->set_r_address(address);
+                               sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       }
+                       else {
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(true);
+                               reloc1.set_r_length(2);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(PPC_RELOC_BR14);
+                       }
+                       relocs.push_back(reloc1);
+                       break;
+
+               case ld::Fixup::kindStoreBigEndian32:
+               case ld::Fixup::kindStoreTargetAddressBigEndian32:
+                       if ( entry.fromTarget != NULL ) {
+                               // this is a pointer-diff
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(false);
+                               sreloc1->set_r_length(2);
+                               if ( entry.toTarget->scope() == ld::Atom::scopeTranslationUnit )
+                                       sreloc1->set_r_type(PPC_RELOC_LOCAL_SECTDIFF);
+                               else
+                                       sreloc1->set_r_type(PPC_RELOC_SECTDIFF);
+                               sreloc1->set_r_address(address);
+                               if ( entry.toTarget == entry.inAtom )
+                                       sreloc1->set_r_value(entry.toTarget->finalAddress()+entry.toAddend);
+                               else
+                                       sreloc1->set_r_value(entry.toTarget->finalAddress());
+                               sreloc2->set_r_scattered(true);
+                               sreloc2->set_r_pcrel(false);
+                               sreloc2->set_r_length(2);
+                               sreloc2->set_r_type(PPC_RELOC_PAIR);
+                               sreloc2->set_r_address(0);
+                               if ( entry.fromTarget == entry.inAtom ) {
+                                       if ( entry.fromAddend > entry.fromTarget->size() )
+                                               sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.offsetInAtom);
+                                       else
+                                               sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.fromAddend);
+                               }
+                               else
+                                       sreloc2->set_r_value(entry.fromTarget->finalAddress());
+                               relocs.push_back(reloc1);
+                               relocs.push_back(reloc2);
+                       }
+                       else {
+                               // regular pointer
+                               if ( !external && (entry.toAddend != 0) ) {
+                                       // use scattered reloc is target offset is non-zero
+                                       sreloc1->set_r_scattered(true);
+                                       sreloc1->set_r_pcrel(false);
+                                       sreloc1->set_r_length(2);
+                                       sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
+                                       sreloc1->set_r_address(address);
+                                       sreloc1->set_r_value(entry.toTarget->finalAddress());
+                               }
+                               else {
+                                       reloc1.set_r_address(address);
+                                       reloc1.set_r_symbolnum(symbolNum);
+                                       reloc1.set_r_pcrel(false);
+                                       reloc1.set_r_length(2);
+                                       reloc1.set_r_extern(external);
+                                       reloc1.set_r_type(GENERIC_RELOC_VANILLA);
+                               }
+                               relocs.push_back(reloc1);
+                       }
+                       break;
+                       
+               case ld::Fixup::kindStoreBigEndian64:
+               case ld::Fixup::kindStoreTargetAddressBigEndian64:
+                       if ( entry.fromTarget != NULL ) {
+                               // this is a pointer-diff
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(false);
+                               sreloc1->set_r_length(3);
+                               if ( entry.toTarget->scope() == ld::Atom::scopeTranslationUnit )
+                                       sreloc1->set_r_type(PPC_RELOC_LOCAL_SECTDIFF);
+                               else
+                                       sreloc1->set_r_type(PPC_RELOC_SECTDIFF);
+                               sreloc1->set_r_address(address);
+                               if ( entry.toTarget == entry.inAtom )
+                                       sreloc1->set_r_value(entry.toTarget->finalAddress()+entry.toAddend);
+                               else
+                                       sreloc1->set_r_value(entry.toTarget->finalAddress());
+                               sreloc2->set_r_scattered(true);
+                               sreloc2->set_r_pcrel(false);
+                               sreloc2->set_r_length(3);
+                               sreloc2->set_r_type(PPC_RELOC_PAIR);
+                               sreloc2->set_r_address(0);
+                               if ( entry.fromTarget == entry.inAtom ) {
+                                       if ( entry.fromAddend > entry.fromTarget->size() )
+                                               sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.offsetInAtom);
+                                       else
+                                               sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.fromAddend);
+                               }
+                               else
+                                       sreloc2->set_r_value(entry.fromTarget->finalAddress());
+                               relocs.push_back(reloc1);
+                               relocs.push_back(reloc2);
+                       }
+                       else {
+                               // regular pointer
+                               if ( !external && (entry.toAddend != 0) ) {
+                                       // use scattered reloc is target offset is non-zero
+                                       sreloc1->set_r_scattered(true);
+                                       sreloc1->set_r_pcrel(false);
+                                       sreloc1->set_r_length(3);
+                                       sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
+                                       sreloc1->set_r_address(address);
+                                       sreloc1->set_r_value(entry.toTarget->finalAddress());
+                               }
+                               else {
+                                       reloc1.set_r_address(address);
+                                       reloc1.set_r_symbolnum(symbolNum);
+                                       reloc1.set_r_pcrel(false);
+                                       reloc1.set_r_length(3);
+                                       reloc1.set_r_extern(external);
+                                       reloc1.set_r_type(GENERIC_RELOC_VANILLA);
+                               }
+                               relocs.push_back(reloc1);
+                       }
+                       break;
+
+               case ld::Fixup::kindStorePPCAbsLow14:
+               case ld::Fixup::kindStorePPCAbsLow16:
+                       if ( !external && (entry.toAddend != 0) ) {
+                               // use scattered reloc if target offset is non-zero
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(false);
+                               sreloc1->set_r_length(2);
+                               sreloc1->set_r_type(entry.kind==ld::Fixup::kindStorePPCAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
+                               sreloc1->set_r_address(address);
+                               sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       }
+                       else {
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(false);
+                               reloc1.set_r_length(2);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(entry.kind==ld::Fixup::kindStorePPCAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
+                       }
+                       if ( external )
+                               reloc2.set_r_address(entry.toAddend >> 16);
+                       else
+                               reloc2.set_r_address((entry.toTarget->finalAddress()+entry.toAddend) >> 16);
+                       reloc2.set_r_symbolnum(0);
+                       reloc2.set_r_pcrel(false);
+                       reloc2.set_r_length(2);
+                       reloc2.set_r_extern(false);
+                       reloc2.set_r_type(PPC_RELOC_PAIR);
+                       relocs.push_back(reloc1);
+                       relocs.push_back(reloc2);
+                       break;
+                       
+               case ld::Fixup::kindStorePPCAbsHigh16:
+                       if ( !external && (entry.toAddend != 0) ) {
+                               // use scattered reloc if target offset is non-zero
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(false);
+                               sreloc1->set_r_length(2);
+                               sreloc1->set_r_type(PPC_RELOC_HI16);
+                               sreloc1->set_r_address(address);
+                               sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       }
+                       else {
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(false);
+                               reloc1.set_r_length(2);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(PPC_RELOC_HI16);
+                       }
+                       if ( external )
+                               reloc2.set_r_address(entry.toAddend & 0x0000FFFF);
+                       else
+                               reloc2.set_r_address((entry.toTarget->finalAddress()+entry.toAddend) & 0x0000FFFF);
+                       reloc2.set_r_symbolnum(0);
+                       reloc2.set_r_pcrel(false);
+                       reloc2.set_r_length(2);
+                       reloc2.set_r_extern(false);
+                       reloc2.set_r_type(PPC_RELOC_PAIR);
+                       relocs.push_back(reloc1);
+                       relocs.push_back(reloc2);
+                       break;
+                       
+               case ld::Fixup::kindStorePPCAbsHigh16AddLow:
+                       if ( !external && (entry.toAddend != 0) ) {
+                               // use scattered reloc if target offset is non-zero
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(false);
+                               sreloc1->set_r_length(2);
+                               sreloc1->set_r_type(PPC_RELOC_HA16);
+                               sreloc1->set_r_address(address);
+                               sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       }
+                       else {
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(false);
+                               reloc1.set_r_length(2);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(PPC_RELOC_HA16);
+                       }
+                       if ( external )
+                               reloc2.set_r_address(entry.toAddend & 0x0000FFFF);
+                       else
+                               reloc2.set_r_address((entry.toTarget->finalAddress()+entry.toAddend) & 0x0000FFFF);
+                       reloc2.set_r_symbolnum(0);
+                       reloc2.set_r_pcrel(false);
+                       reloc2.set_r_length(2);
+                       reloc2.set_r_extern(false);
+                       reloc2.set_r_type(PPC_RELOC_PAIR);
+                       relocs.push_back(reloc1);
+                       relocs.push_back(reloc2);
+                       break;
+                       
+               case ld::Fixup::kindStorePPCPicLow14:
+               case ld::Fixup::kindStorePPCPicLow16:
+                       fromAddr = entry.fromTarget->finalAddress() + entry.fromAddend;
+                       toAddr = entry.toTarget->finalAddress() + entry.toAddend;
+                       sreloc1->set_r_scattered(true);
+                       sreloc1->set_r_pcrel(false);
+                       sreloc1->set_r_length(2);
+                       sreloc1->set_r_type(entry.kind == ld::Fixup::kindStorePPCPicLow16 ? PPC_RELOC_LO16_SECTDIFF : PPC_RELOC_LO14_SECTDIFF);
+                       sreloc1->set_r_address(address);
+                       sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       sreloc2->set_r_scattered(true);
+                       sreloc2->set_r_pcrel(false);
+                       sreloc2->set_r_length(2);
+                       sreloc2->set_r_type(PPC_RELOC_PAIR);
+                       sreloc2->set_r_address(((toAddr-fromAddr) >> 16) & 0xFFFF);
+                       sreloc2->set_r_value(fromAddr);
+                       relocs.push_back(reloc1);
+                       relocs.push_back(reloc2);
+                       break;
+                       
+               case ld::Fixup::kindStorePPCPicHigh16AddLow:
+                       fromAddr = entry.fromTarget->finalAddress() + entry.fromAddend;
+                       toAddr = entry.toTarget->finalAddress() + entry.toAddend;
+                       sreloc1->set_r_scattered(true);
+                       sreloc1->set_r_pcrel(false);
+                       sreloc1->set_r_length(2);
+                       sreloc1->set_r_type(PPC_RELOC_HA16_SECTDIFF);
+                       sreloc1->set_r_address(address);
+                       sreloc1->set_r_value(entry.toTarget->finalAddress());
+                       sreloc2->set_r_scattered(true);
+                       sreloc2->set_r_pcrel(false);
+                       sreloc2->set_r_length(2);
+                       sreloc2->set_r_type(PPC_RELOC_PAIR);
+                       sreloc2->set_r_address((toAddr-fromAddr) & 0xFFFF);
+                       sreloc2->set_r_value(fromAddr);
+                       relocs.push_back(reloc1);
+                       relocs.push_back(reloc2);
+                       break;
+                       
+               default:
+                       assert(0 && "need to handle -r reloc");
+               
+       }
+}
+
+template <typename A>
+void SectionRelocationsAtom<A>::addSectionReloc(ld::Internal::FinalSection*    sect, ld::Fixup::Kind kind, 
+                                                                                               const ld::Atom* inAtom, uint32_t offsetInAtom,  
+                                                                                               bool toTargetUsesExternalReloc ,bool fromTargetExternalReloc,
+                                                                                               const ld::Atom* toTarget, uint64_t toAddend, 
+                                                                                               const ld::Atom* fromTarget, uint64_t fromAddend)
+{
+       Entry entry;
+       entry.kind = kind;
+       entry.toTargetUsesExternalReloc = toTargetUsesExternalReloc;
+       entry.fromTargetUsesExternalReloc = fromTargetExternalReloc;
+       entry.inAtom = inAtom;
+       entry.offsetInAtom = offsetInAtom;
+       entry.toTarget = toTarget;
+       entry.toAddend = toAddend;
+       entry.fromTarget = fromTarget;
+       entry.fromAddend = fromAddend;
+       
+       static ld::Internal::FinalSection* lastSection = NULL;
+       static SectionAndEntries* lastSectionAndEntries = NULL;
+               
+       if ( sect != lastSection ) {
+               for(typename std::vector<SectionAndEntries>::iterator it=_entriesBySection.begin(); it != _entriesBySection.end(); ++it) {
+                       if ( sect == it->sect ) {
+                               lastSection = sect;
+                               lastSectionAndEntries = &*it;
+                               break;
+                       }
+               }
+               if ( sect != lastSection ) {
+                       SectionAndEntries tmp;
+                       tmp.sect = sect;
+                       _entriesBySection.push_back(tmp);
+                       lastSection = sect;
+                       lastSectionAndEntries = &_entriesBySection.back();
+               }
+       }
+       lastSectionAndEntries->entries.push_back(entry);
+}
+
+template <typename A>
+void SectionRelocationsAtom<A>::encode()
+{
+       // convert each Entry record to one or two reloc records
+       for(typename std::vector<SectionAndEntries>::iterator it=_entriesBySection.begin(); it != _entriesBySection.end(); ++it) {
+               SectionAndEntries& se = *it;
+               for(typename std::vector<Entry>::iterator eit=se.entries.begin(); eit != se.entries.end(); ++eit) {
+                       encodeSectionReloc(se.sect, *eit, se.relocs);
+               }
+       }
+       
+       // update sections with start and count or relocs
+       uint32_t index = 0;
+       for(typename std::vector<SectionAndEntries>::iterator it=_entriesBySection.begin(); it != _entriesBySection.end(); ++it) {
+               SectionAndEntries& se = *it;
+               se.sect->relocStart = index;
+               se.sect->relocCount = se.relocs.size();
+               index += se.sect->relocCount;
+       }
+
+}
+
+
+
+template <typename A>
+class IndirectSymbolTableAtom : public ClassicLinkEditAtom
+{
+public:
+                                                                                               IndirectSymbolTableAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+                                                                                                       : ClassicLinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { }
+
+       // overrides of ld::Atom
+       virtual const char*                                                     name() const            { return "indirect symbol table"; }
+       virtual uint64_t                                                        size() const;
+       virtual void                                                            copyRawContent(uint8_t buffer[]) const; 
+       // overrides of ClassicLinkEditAtom
+       virtual void                                                            encode();
+
+private:
+       typedef typename A::P                                           P;
+       typedef typename A::P::E                                        E;
+       typedef typename A::P::uint_t                           pint_t;
+       
+       void                                                                            encodeStubSection(ld::Internal::FinalSection* sect);
+       void                                                                            encodeLazyPointerSection(ld::Internal::FinalSection* sect);
+       void                                                                            encodeNonLazyPointerSection(ld::Internal::FinalSection* sect);
+       uint32_t                                                                        symIndexOfStubAtom(const ld::Atom*);
+       uint32_t                                                                        symIndexOfLazyPointerAtom(const ld::Atom*);
+       uint32_t                                                                        symIndexOfNonLazyPointerAtom(const ld::Atom*);
+       uint32_t                                                                        symbolIndex(const ld::Atom*);
+       bool                                                                            kextBundlesDontHaveIndirectSymbolTable();
+
+
+       std::vector<uint32_t>                                           _entries;
+       
+       static ld::Section                      _s_section;
+};
+
+template <typename A>
+ld::Section IndirectSymbolTableAtom<A>::_s_section("__LINKEDIT", "__ind_sym_tab", ld::Section::typeLinkEdit, true);
+
+
+
+
+template <typename A>
+uint32_t IndirectSymbolTableAtom<A>::symbolIndex(const ld::Atom* atom)
+{
+       std::map<const ld::Atom*, uint32_t>::iterator pos = this->_writer._atomToSymbolIndex.find(atom);
+       if ( pos != this->_writer._atomToSymbolIndex.end() )
+               return pos->second;
+       //fprintf(stderr, "_atomToSymbolIndex content:\n");
+       //for(std::map<const ld::Atom*, uint32_t>::iterator it = this->_writer._atomToSymbolIndex.begin(); it != this->_writer._atomToSymbolIndex.end(); ++it) {
+       //              fprintf(stderr, "%p(%s) => %d\n", it->first, it->first->name(), it->second);
+       //}
+       throwf("internal error: atom not found in symbolIndex(%s)", atom->name());
+}
+
+template <typename A>
+uint32_t IndirectSymbolTableAtom<A>::symIndexOfStubAtom(const ld::Atom* stubAtom)
+{
+       for (ld::Fixup::iterator fit = stubAtom->fixupsBegin(); fit != stubAtom->fixupsEnd(); ++fit) {
+               if ( fit->binding == ld::Fixup::bindingDirectlyBound ) {
+                       assert((fit->u.target->contentType() == ld::Atom::typeLazyPointer) 
+                                       || (fit->u.target->contentType() == ld::Atom::typeLazyDylibPointer));
+                       return symIndexOfLazyPointerAtom(fit->u.target);
+               }
+       }
+       throw "internal error: stub missing fixup to lazy pointer";
+}
+
+
+template <typename A>
+uint32_t IndirectSymbolTableAtom<A>::symIndexOfLazyPointerAtom(const ld::Atom* lpAtom)
+{
+       for (ld::Fixup::iterator fit = lpAtom->fixupsBegin(); fit != lpAtom->fixupsEnd(); ++fit) {
+               if ( fit->kind == ld::Fixup::kindLazyTarget ) {
+                       assert(fit->binding == ld::Fixup::bindingDirectlyBound);
+                       return symbolIndex(fit->u.target);
+               }
+       }
+       throw "internal error: lazy pointer missing fixupLazyTarget fixup";
+}
+
+template <typename A>
+uint32_t IndirectSymbolTableAtom<A>::symIndexOfNonLazyPointerAtom(const ld::Atom* nlpAtom)
+{
+       //fprintf(stderr, "symIndexOfNonLazyPointerAtom(%p) %s\n", nlpAtom, nlpAtom->name());
+       for (ld::Fixup::iterator fit = nlpAtom->fixupsBegin(); fit != nlpAtom->fixupsEnd(); ++fit) {
+               // non-lazy-pointer to a stripped symbol => no symbol index
+               if ( fit->clusterSize != ld::Fixup::k1of1 )
+                       return INDIRECT_SYMBOL_LOCAL;
+               const ld::Atom* target;
+               switch ( fit->binding ) {
+                       case ld::Fixup::bindingDirectlyBound:
+                               target = fit->u.target;
+                               break;
+                       case ld::Fixup::bindingsIndirectlyBound:
+                               target = _state.indirectBindingTable[fit->u.bindingIndex];
+                               break;
+                       default:
+                               throw "internal error: unexpected non-lazy pointer binding";
+               }
+               // Special case non-lazy-pointer slot used to point to "dyld_stub_binder"
+               // That slot is never bound using indirect symbol table
+               if ( target == _state.compressedFastBinderProxy )
+                       return INDIRECT_SYMBOL_ABS;
+               bool targetIsGlobal = (target->scope() == ld::Atom::scopeGlobal);
+               switch ( target->definition() ) {
+                       case ld::Atom::definitionRegular:
+                               if ( targetIsGlobal ) {
+                                       if ( _options.outputKind() == Options::kObjectFile ) {
+                                               // nlpointer to global symbol uses indirect symbol table in .o files
+                                               return symbolIndex(target);
+                                       } 
+                                       else if ( target->combine() == ld::Atom::combineByName ) {
+                                               // dyld needs to bind nlpointer to global weak def
+                                               return symbolIndex(target);
+                                       }
+                                       else if ( _options.nameSpace() != Options::kTwoLevelNameSpace ) {
+                                               // dyld needs to bind nlpointer to global def linked for flat namespace
+                                               return symbolIndex(target);
+                                       }
+                               }
+                               break;
+                       case ld::Atom::definitionTentative:
+                       case ld::Atom::definitionAbsolute:
+                               if ( _options.outputKind() == Options::kObjectFile ) {
+                                       // tentative def in .o file always uses symbol index
+                                       return symbolIndex(target);
+                               }
+                               // dyld needs to bind nlpointer to global def linked for flat namespace
+                               if ( targetIsGlobal && _options.nameSpace() != Options::kTwoLevelNameSpace ) 
+                                       return symbolIndex(target);
+                               break;
+                       case ld::Atom::definitionProxy:
+                               // dyld needs to bind nlpointer to something in another dylib
+                               {
+                                       const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(target->file());
+                                       if ( (dylib != NULL) && dylib->willBeLazyLoadedDylib() )
+                                               throwf("illegal data reference to %s in lazy loaded dylib %s", target->name(), dylib->path());
+                               }
+                               return symbolIndex(target);
+               }
+       }
+       if ( nlpAtom->fixupsBegin() == nlpAtom->fixupsEnd() ) {
+               // no fixups means this is the ImageLoader cache slot
+               return INDIRECT_SYMBOL_ABS;
+       }
+       
+       // The magic index INDIRECT_SYMBOL_LOCAL tells dyld it should does not need to bind
+       // this non-lazy pointer.
+       return INDIRECT_SYMBOL_LOCAL;
+}
+
+
+
+template <typename A>
+void IndirectSymbolTableAtom<A>::encodeStubSection(ld::Internal::FinalSection* sect)
+{
+       sect->indirectSymTabStartIndex = _entries.size();
+       sect->indirectSymTabElementSize = sect->atoms[0]->size();
+       for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+               _entries.push_back(symIndexOfStubAtom(*ait));
+       }
+}
+
+template <typename A>
+void IndirectSymbolTableAtom<A>::encodeLazyPointerSection(ld::Internal::FinalSection* sect)
+{
+       sect->indirectSymTabStartIndex = _entries.size();
+       for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+               _entries.push_back(symIndexOfLazyPointerAtom(*ait));
+       }
+}
+
+template <typename A>
+void IndirectSymbolTableAtom<A>::encodeNonLazyPointerSection(ld::Internal::FinalSection* sect)
+{
+       sect->indirectSymTabStartIndex = _entries.size();
+       for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+               _entries.push_back(symIndexOfNonLazyPointerAtom(*ait));
+       }
+}
+
+template <typename A>
+bool IndirectSymbolTableAtom<A>::kextBundlesDontHaveIndirectSymbolTable()
+{
+       return true;    
+}
+
+template <typename A>
+void IndirectSymbolTableAtom<A>::encode()
+{
+       // static executables should not have an indirect symbol table
+       if ( this->_options.outputKind() == Options::kStaticExecutable ) 
+               return;
+
+       // x86_64 kext bundles should not have an indirect symbol table
+       if ( (this->_options.outputKind() == Options::kKextBundle) && kextBundlesDontHaveIndirectSymbolTable() ) 
+               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;
+               switch ( sect->type() ) {
+                       case ld::Section::typeStub:
+                       case ld::Section::typeStubClose:
+                               this->encodeStubSection(sect);
+                               break;
+                       case ld::Section::typeLazyPointerClose:
+                       case ld::Section::typeLazyPointer:
+                       case ld::Section::typeLazyDylibPointer:
+                               this->encodeLazyPointerSection(sect);
+                               break;
+                       case ld::Section::typeNonLazyPointer:
+                               this->encodeNonLazyPointerSection(sect);
+                               break;
+                       default:
+                               break;
+               }
+       }
+}
+
+template <typename A>
+uint64_t IndirectSymbolTableAtom<A>::size() const
+{
+       return _entries.size() * sizeof(uint32_t);
+}
+
+template <typename A>
+void IndirectSymbolTableAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+       uint32_t* array = (uint32_t*)buffer;
+       for(unsigned long i=0; i < _entries.size(); ++i) {
+               E::set32(array[i], _entries[i]);
+       }
+}
+
+
+
+
+
+
+
+
+} // namespace tool 
+} // namespace ld 
+
+#endif // __LINKEDIT_CLASSIC_HPP__
diff --git a/src/ld/MachOReaderDylib.hpp b/src/ld/MachOReaderDylib.hpp
deleted file mode 100644 (file)
index 5a6c553..0000000
+++ /dev/null
@@ -1,1048 +0,0 @@
-/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
- *
- * Copyright (c) 2005-2007 Apple Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-#ifndef __OBJECT_FILE_DYLIB_MACH_O__
-#define __OBJECT_FILE_DYLIB_MACH_O__
-
-#include <stdint.h>
-#include <math.h>
-#include <unistd.h>
-#include <sys/param.h>
-
-
-#include <vector>
-#include <set>
-#include <algorithm>
-#include <ext/hash_map>
-
-#include "MachOFileAbstraction.hpp"
-#include "MachOTrie.hpp"
-#include "ObjectFile.h"
-
-//
-//
-//     To implement architecture xxx, you must write template specializations for the following method:
-//                     Reader<xxx>::validFile()
-//
-//
-
-
-
-
-namespace mach_o {
-namespace dylib {
-
-
-// forward reference
-template <typename A> class Reader;
-
-
-class Segment : public ObjectFile::Segment
-{
-public:
-                                                               Segment(const char* name)               { fName = name; }
-       virtual const char*                     getName() const                                 { return fName; }
-       virtual bool                            isContentReadable() const               { return true; }
-       virtual bool                            isContentWritable() const               { return false; }
-       virtual bool                            isContentExecutable() const             { return false; }
-private:
-       const char*                                     fName;
-};
-
-
-//
-// An ExportAtom has no content.  It exists so that the linker can track which imported
-// symbols came from which dynamic libraries.
-//
-template <typename A>
-class ExportAtom : public ObjectFile::Atom
-{
-public:
-       virtual ObjectFile::Reader*                                     getFile() const                         { return &fOwner; }
-       virtual bool                                                            getTranslationUnitSource(const char** dir, const char** name) const { return false; }
-       virtual const char*                                                     getName() const                         { return fName; }
-       virtual const char*                                                     getDisplayName() const          { return fName; }
-       virtual Scope                                                           getScope() const                        { return ObjectFile::Atom::scopeGlobal; }
-       virtual DefinitionKind                                          getDefinitionKind() const       { return fWeakDefinition ? kExternalWeakDefinition : kExternalDefinition; }
-       virtual SymbolTableInclusion                            getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableIn; }
-       virtual bool                                                            dontDeadStrip() const           { return false; }
-       virtual bool                                                            isZeroFill() const                      { return false; }
-       virtual bool                                                            isThumb() const                         { return false; }
-       virtual uint64_t                                                        getSize() const                         { return 0; }
-       virtual std::vector<ObjectFile::Reference*>&  getReferences() const             { return fgEmptyReferenceList; }
-       virtual bool                                                            mustRemainInSection() const { return false; }
-       virtual const char*                                                     getSectionName() const          { return "._imports"; }
-       virtual Segment&                                                        getSegment() const                      { return fgImportSegment; }
-       virtual ObjectFile::Atom&                                       getFollowOnAtom() const         { return *((ObjectFile::Atom*)NULL); }
-       virtual uint32_t                                                        getOrdinal() const                      { return fOrdinal; }
-       virtual std::vector<ObjectFile::LineInfo>*      getLineInfo() const                     { return NULL; }
-       virtual ObjectFile::Alignment                           getAlignment() const            { return ObjectFile::Alignment(0); }
-       virtual void                                                            copyRawContent(uint8_t buffer[]) const  {}
-
-       virtual void                                                            setScope(Scope)                         { }
-
-protected:
-       friend class Reader<A>;
-       typedef typename A::P                                   P;
-
-                                                                                       ExportAtom(ObjectFile::Reader& owner, const char* name, bool weak, uint32_t ordinal)
-                                                                                               : fOwner(owner), fName(name), fOrdinal(ordinal), fWeakDefinition(weak) {}
-       virtual                                                                 ~ExportAtom() {}
-
-       ObjectFile::Reader&                                             fOwner;
-       const char*                                                             fName;
-       uint32_t                                                                fOrdinal;
-       bool                                                                    fWeakDefinition;
-
-       static std::vector<ObjectFile::Reference*>      fgEmptyReferenceList;
-       static Segment                                                          fgImportSegment;
-};
-
-template <typename A>
-Segment                                                                ExportAtom<A>::fgImportSegment("__LINKEDIT");
-
-template <typename A>
-std::vector<ObjectFile::Reference*>    ExportAtom<A>::fgEmptyReferenceList;
-
-
-
-class ImportReference : public ObjectFile::Reference
-{
-public:
-                                                       ImportReference(const char* name)
-                                                               : fTarget(NULL), fTargetName(strdup(name))  {}
-       virtual                                 ~ImportReference() {}
-
-
-       virtual ObjectFile::Reference::TargetBinding    getTargetBinding() const        { return (fTarget==NULL) ? ObjectFile::Reference::kUnboundByName : ObjectFile::Reference::kBoundByName; }
-       virtual ObjectFile::Reference::TargetBinding    getFromTargetBinding() const{ return ObjectFile::Reference::kDontBind; }
-       virtual uint8_t                                                                 getKind() const                         { return 0; }
-       virtual uint64_t                                                                getFixUpOffset() const          { return 0; }
-       virtual const char*                                                             getTargetName() const           { return fTargetName; }
-       virtual ObjectFile::Atom&                                               getTarget() const                       { return *((ObjectFile::Atom*)fTarget); }
-       virtual uint64_t                                                                getTargetOffset() const         { return 0; }
-       virtual ObjectFile::Atom&                                               getFromTarget() const           { return *((ObjectFile::Atom*)NULL); }
-       virtual const char*                                                             getFromTargetName() const       { return NULL; }
-       virtual uint64_t                                                                getFromTargetOffset() const { return 0; }
-       virtual void                                                                    setTarget(ObjectFile::Atom& atom, uint64_t offset) { fTarget = &atom; }
-       virtual void                                                                    setFromTarget(ObjectFile::Atom&) { throw "can't set from target"; }
-       virtual const char*                                                             getDescription() const          { return "dylib import reference"; }
-
-private:
-       const ObjectFile::Atom* fTarget;
-       const char*                             fTargetName;
-};
-
-
-//
-// An ImportAtom has no content.  It exists so that when linking a main executable flat-namespace
-// the imports of all flat dylibs are checked
-//
-template <typename A>
-class ImportAtom : public ObjectFile::Atom
-{
-public:
-       virtual ObjectFile::Reader*                                     getFile() const                         { return &fOwner; }
-       virtual bool                                                            getTranslationUnitSource(const char** dir, const char** name) const { return false; }
-       virtual const char*                                                     getName() const                         { return "flat-imports"; }
-       virtual const char*                                                     getDisplayName() const          { return "flat_namespace undefines"; }
-       virtual Scope                                                           getScope() const                        { return ObjectFile::Atom::scopeTranslationUnit; }
-       virtual DefinitionKind                                          getDefinitionKind() const       { return kRegularDefinition; }
-       virtual SymbolTableInclusion                            getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
-       virtual bool                                                            dontDeadStrip() const           { return false; }
-       virtual bool                                                            isZeroFill() const                      { return false; }
-       virtual bool                                                            isThumb() const                         { return false; }
-       virtual uint64_t                                                        getSize() const                         { return 0; }
-       virtual std::vector<ObjectFile::Reference*>&  getReferences() const             { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
-       virtual bool                                                            mustRemainInSection() const { return false; }
-       virtual const char*                                                     getSectionName() const          { return "._imports"; }
-       virtual Segment&                                                        getSegment() const                      { return fgImportSegment; }
-       virtual ObjectFile::Atom&                                       getFollowOnAtom() const         { return *((ObjectFile::Atom*)NULL); }
-       virtual uint32_t                                                        getOrdinal() const                      { return fOrdinal; }
-       virtual std::vector<ObjectFile::LineInfo>*      getLineInfo() const                     { return NULL; }
-       virtual ObjectFile::Alignment                           getAlignment() const            { return ObjectFile::Alignment(0); }
-       virtual void                                                            copyRawContent(uint8_t buffer[]) const  {}
-
-       virtual void                                                            setScope(Scope)                         { }
-
-protected:
-       friend class Reader<A>;
-       typedef typename A::P                                   P;
-
-                                                                                       ImportAtom(ObjectFile::Reader& owner, uint32_t ordinal, std::vector<const char*>& imports)
-                                                                                               : fOwner(owner), fOrdinal(ordinal) { makeReferences(imports); }
-       virtual                                                                 ~ImportAtom() {}
-       void                                                                    makeReferences(std::vector<const char*>& imports) {
-                                                                                               for (std::vector<const char*>::iterator it=imports.begin(); it != imports.end(); ++it) {
-                                                                                                       fReferences.push_back(new ImportReference(*it));
-                                                                                               }
-                                                                                       }
-
-
-       ObjectFile::Reader&                                             fOwner;
-       uint32_t                                                                fOrdinal;
-       std::vector<ObjectFile::Reference*>             fReferences;
-       
-       static Segment                                                  fgImportSegment;
-};
-
-template <typename A>
-Segment                                                                ImportAtom<A>::fgImportSegment("__LINKEDIT");
-
-
-
-
-//
-// The reader for a dylib extracts all exported symbols names from the memory-mapped
-// dylib, builds a hash table, then unmaps the file.  This is an important memory
-// savings for large dylibs.
-//
-template <typename A>
-class Reader : public ObjectFile::Reader
-{
-public:
-       static bool                                                                             validFile(const uint8_t* fileContent, bool executableOrDylib);
-                                                                                                       Reader(const uint8_t* fileContent, uint64_t fileLength, const char* path,
-                                                                                                               const LibraryOptions& dylibOptions, const ObjectFile::ReaderOptions& options,
-                                                                                                               uint32_t ordinalBase);
-       virtual                                                                                 ~Reader() {}
-
-       virtual const char*                                                             getPath()                                       { return fPath; }
-       virtual time_t                                                                  getModificationTime()           { return 0; }
-       virtual DebugInfoKind                                                   getDebugInfoKind()                      { return ObjectFile::Reader::kDebugInfoNone; }
-       virtual std::vector<class ObjectFile::Atom*>&   getAtoms();
-       virtual std::vector<class ObjectFile::Atom*>*   getJustInTimeAtomsFor(const char* name);
-       virtual std::vector<Stab>*                                              getStabs()                                      { return NULL; }
-       virtual ObjectFile::Reader::ObjcConstraint              getObjCConstraint()                     { return fObjcContraint; }
-       virtual const char*                                                             getInstallPath()                        { return fDylibInstallPath; }
-       virtual uint32_t                                                                getTimestamp()                          { return fDylibTimeStamp; }
-       virtual uint32_t                                                                getCurrentVersion()                     { return fDylibtCurrentVersion; }
-       virtual uint32_t                                                                getCompatibilityVersion()       { return fDylibCompatibilityVersion; }
-       virtual void                                                                    processIndirectLibraries(DylibHander* handler);
-       virtual void                                                                    setExplicitlyLinked()           { fExplicitlyLinked = true; }
-       virtual bool                                                                    explicitlyLinked()                      { return fExplicitlyLinked; }
-       virtual bool                                                                    implicitlyLinked()                      { return fImplicitlyLinked; }
-       virtual bool                                                                    providedExportAtom()            { return fProvidedAtom; }
-       virtual const char*                                                             parentUmbrella()                        { return fParentUmbrella; }
-       virtual std::vector<const char*>*                               getAllowableClients();
-       virtual bool                                                                    hasWeakExternals()                      { return fHasWeakExports; }
-       virtual bool                                                                    deadStrippable()                        { return fDeadStrippable; }
-       virtual bool                                                                    isLazyLoadedDylib()                     { return fLazyLoaded; }
-
-       virtual void                                                                    setImplicitlyLinked()           { fImplicitlyLinked = true; }
-
-protected:
-
-       struct ReExportChain { ReExportChain* prev; Reader<A>* reader; };
-
-       void                                                                                    assertNoReExportCycles(ReExportChain*);
-
-private:
-       typedef typename A::P                                           P;
-       typedef typename A::P::E                                        E;
-
-       class CStringEquals
-       {
-       public:
-               bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
-       };
-       struct AtomAndWeak { ObjectFile::Atom* atom; bool weak; uint32_t ordinal; };
-       typedef __gnu_cxx::hash_map<const char*, AtomAndWeak, __gnu_cxx::hash<const char*>, CStringEquals> NameToAtomMap;
-       typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals>  NameSet;
-       typedef typename NameToAtomMap::iterator                NameToAtomMapIterator;
-
-       struct PathAndFlag { const char* path; bool reExport; };
-
-       bool                                                                            isPublicLocation(const char* path);
-       void                                                                            addSymbol(const char* name, bool weak);
-       void                                                                            addDyldFastStub();
-       void                                                                            buildExportHashTableFromExportInfo(const macho_dyld_info_command<P>* dyldInfo,
-                                                                                                                                                               const uint8_t* fileContent);
-       void                                                                            buildExportHashTableFromSymbolTable(const macho_dysymtab_command<P>* dynamicInfo, 
-                                                                                                               const macho_nlist<P>* symbolTable, const char* strings,
-                                                                                                               const uint8_t* fileContent);
-
-       const char*                                                                     fPath;
-       const char*                                                                     fParentUmbrella;
-       std::vector<const char*>                                        fAllowableClients;
-       const char*                                                                     fDylibInstallPath;
-       uint32_t                                                                        fDylibTimeStamp;
-       uint32_t                                                                        fDylibtCurrentVersion;
-       uint32_t                                                                        fDylibCompatibilityVersion;
-       uint32_t                                                                        fReExportedOrdinal;
-       std::vector<PathAndFlag>                                        fDependentLibraryPaths;
-       NameToAtomMap                                                           fAtoms;
-       NameSet                                                                         fIgnoreExports;
-       bool                                                                            fNoRexports;
-       bool                                                                            fHasWeakExports;
-       bool                                                                            fDeadStrippable;
-       const bool                                                                      fLinkingFlat;
-       const bool                                                                      fLinkingMainExecutable;
-       bool                                                                            fExplictReExportFound;
-       bool                                                                            fExplicitlyLinked;
-       bool                                                                            fImplicitlyLinked;
-       bool                                                                            fProvidedAtom;
-       bool                                                                            fImplicitlyLinkPublicDylibs;
-       bool                                                                            fLazyLoaded;
-       ObjectFile::Reader::ObjcConstraint                      fObjcContraint;
-       std::vector<ObjectFile::Reader*>                        fReExportedChildren;
-       const ObjectFile::ReaderOptions::MacVersionMin          fMacDeploymentVersionMin;
-       const ObjectFile::ReaderOptions::IPhoneVersionMin       fIPhoneDeploymentVersionMin;
-       std::vector<class ObjectFile::Atom*>            fFlatImports;
-
-       static bool                                                                     fgLogHashtable;
-       static std::vector<class ObjectFile::Atom*>     fgEmptyAtomList;
-};
-
-template <typename A>
-std::vector<class ObjectFile::Atom*>   Reader<A>::fgEmptyAtomList;
-template <typename A>
-bool                                                                   Reader<A>::fgLogHashtable = false;
-
-
-template <typename A>
-Reader<A>::Reader(const uint8_t* fileContent, uint64_t fileLength, const char* path, 
-               const LibraryOptions& dylibOptions, 
-               const ObjectFile::ReaderOptions& options, uint32_t ordinalBase)
-       : fParentUmbrella(NULL), fDylibInstallPath(NULL), fDylibTimeStamp(0), fDylibtCurrentVersion(0), 
-       fDylibCompatibilityVersion(0), fReExportedOrdinal(ordinalBase), fLinkingFlat(options.fFlatNamespace), 
-       fLinkingMainExecutable(options.fLinkingMainExecutable), fExplictReExportFound(false), 
-       fExplicitlyLinked(false), fImplicitlyLinked(false), fProvidedAtom(false), 
-       fImplicitlyLinkPublicDylibs(options.fImplicitlyLinkPublicDylibs), fLazyLoaded(dylibOptions.fLazyLoad),
-       fObjcContraint(ObjectFile::Reader::kObjcNone),
-       fMacDeploymentVersionMin(options.fMacVersionMin),
-       fIPhoneDeploymentVersionMin(options.fIPhoneVersionMin)
-{
-       // sanity check
-       if ( ! validFile(fileContent, dylibOptions.fBundleLoader) )
-               throw "not a valid mach-o object file";
-
-       fPath = strdup(path);
-       
-       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());
-
-       // write out path for -whatsloaded option
-       if ( options.fLogAllFiles )
-               printf("%s\n", path);
-
-       if ( options.fRootSafe && ((header->flags() & MH_ROOT_SAFE) == 0) )
-               warning("using -root_safe but linking against %s which is not root safe", path);
-
-       if ( options.fSetuidSafe && ((header->flags() & MH_SETUID_SAFE) == 0) )
-               warning("using -setuid_safe but linking against %s which is not setuid safe", path);
-
-       // a "blank" stub has zero load commands
-       if ( (header->filetype() == MH_DYLIB_STUB) && (cmd_count == 0) ) {      
-               // no further processing needed
-               munmap((caddr_t)fileContent, fileLength);
-               return;
-       }
-
-
-       // optimize the case where we know there is no reason to look at indirect dylibs
-       fNoRexports = (header->flags() & MH_NO_REEXPORTED_DYLIBS);
-       fHasWeakExports = (header->flags() & MH_WEAK_DEFINES);
-       fDeadStrippable = (header->flags() & MH_DEAD_STRIPPABLE_DYLIB);
-       bool trackDependentLibraries = !fNoRexports || options.fFlatNamespace;
-       
-       // pass 1 builds list of all dependent libraries
-       const macho_load_command<P>* cmd = cmds;
-       if ( trackDependentLibraries ) {
-               for (uint32_t i = 0; i < cmd_count; ++i) {
-                       switch (cmd->cmd()) {
-                               case LC_REEXPORT_DYLIB:
-                                       fExplictReExportFound = true;
-                                       // fall into next case
-                               case LC_LOAD_DYLIB:
-                               case LC_LOAD_WEAK_DYLIB:
-                                       PathAndFlag entry;
-                                       entry.path = strdup(((struct macho_dylib_command<P>*)cmd)->name());
-                                       entry.reExport = (cmd->cmd() == LC_REEXPORT_DYLIB);
-                                       fDependentLibraryPaths.push_back(entry);
-                                       break;
-                       }
-                       cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
-                       if ( cmd > cmdsEnd )
-                               throwf("malformed dylb, load command #%d is outside size of load commands in %s", i, path);
-               }
-       }
-       
-       // pass 2 determines re-export info
-       const macho_dysymtab_command<P>* dynamicInfo = NULL;
-       const macho_dyld_info_command<P>* dyldInfo = NULL;
-       const macho_nlist<P>* symbolTable = NULL;
-       const char*     strings = NULL;
-       cmd = cmds;
-       for (uint32_t i = 0; i < cmd_count; ++i) {
-               switch (cmd->cmd()) {
-                       case LC_SYMTAB:
-                               {
-                                       const macho_symtab_command<P>* symtab = (macho_symtab_command<P>*)cmd;
-                                       symbolTable = (const macho_nlist<P>*)((char*)header + symtab->symoff());
-                                       strings = (char*)header + symtab->stroff();
-                               }
-                               break;
-                       case LC_DYSYMTAB:
-                               dynamicInfo = (macho_dysymtab_command<P>*)cmd;
-                               break;
-                       case LC_DYLD_INFO:
-                       case LC_DYLD_INFO_ONLY:
-                               dyldInfo = (macho_dyld_info_command<P>*)cmd;
-                               break;
-                       case LC_ID_DYLIB:
-                               {
-                               macho_dylib_command<P>* dylibID = (macho_dylib_command<P>*)cmd;
-                               fDylibInstallPath                       = strdup(dylibID->name());
-                               fDylibTimeStamp                         = dylibID->timestamp();
-                               fDylibtCurrentVersion           = dylibID->current_version();
-                               fDylibCompatibilityVersion      = dylibID->compatibility_version();
-                               }
-                               break;
-                       case LC_SUB_UMBRELLA:
-                               if ( trackDependentLibraries ) {
-                                       const char* frameworkLeafName = ((macho_sub_umbrella_command<P>*)cmd)->sub_umbrella();
-                                       for (typename std::vector<PathAndFlag>::iterator it = fDependentLibraryPaths.begin(); it != fDependentLibraryPaths.end(); it++) {
-                                               const char* dylibName = it->path;
-                                               const char* lastSlash = strrchr(dylibName, '/');
-                                               if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], frameworkLeafName) == 0) )
-                                                       it->reExport = true;
-                                       }
-                               }
-                               break;
-                       case LC_SUB_LIBRARY:
-                               if ( trackDependentLibraries) {
-                                       const char* dylibBaseName = ((macho_sub_library_command<P>*)cmd)->sub_library();
-                                       for (typename std::vector<PathAndFlag>::iterator it = fDependentLibraryPaths.begin(); it != fDependentLibraryPaths.end(); it++) {
-                                               const char* dylibName = it->path;
-                                               const char* lastSlash = strrchr(dylibName, '/');
-                                               const char* leafStart = &lastSlash[1];
-                                               if ( lastSlash == NULL )
-                                                       leafStart = dylibName;
-                                               const char* firstDot = strchr(leafStart, '.');
-                                               int len = strlen(leafStart);
-                                               if ( firstDot != NULL )
-                                                       len = firstDot - leafStart;
-                                               if ( strncmp(leafStart, dylibBaseName, len) == 0 )
-                                                       it->reExport = true;
-                                       }
-                               }
-                               break;
-                       case LC_SUB_FRAMEWORK:
-                               fParentUmbrella = strdup(((macho_sub_framework_command<P>*)cmd)->umbrella());
-                               break;
-                       case macho_segment_command<P>::CMD:
-                               // check for Objective-C info
-                               if ( strcmp(((macho_segment_command<P>*)cmd)->segname(), "__OBJC") == 0 ) {
-                                       const macho_segment_command<P>* segment = (macho_segment_command<P>*)cmd;
-                                       const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segment + sizeof(macho_segment_command<P>));
-                                       const macho_section<P>* const sectionsEnd = &sectionsStart[segment->nsects()];
-                                       for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
-                                                       if ( strcmp(sect->sectname(), "__image_info") == 0 ) {
-                                                       //      struct objc_image_info  {
-                                                       //              uint32_t        version;        // initially 0
-                                                       //              uint32_t        flags;
-                                                       //      };
-                                                       // #define OBJC_IMAGE_SUPPORTS_GC   2
-                                                       // #define OBJC_IMAGE_GC_ONLY       4
-                                                       //
-                                                       const uint32_t* contents = (uint32_t*)(&fileContent[sect->offset()]);
-                                                       if ( (sect->size() >= 8) && (contents[0] == 0) ) {
-                                                               uint32_t flags = E::get32(contents[1]);
-                                                               if ( (flags & 4) == 4 )
-                                                                       fObjcContraint = ObjectFile::Reader::kObjcGC;
-                                                               else if ( (flags & 2) == 2 )
-                                                                       fObjcContraint = ObjectFile::Reader::kObjcRetainReleaseOrGC;
-                                                               else
-                                                                       fObjcContraint = ObjectFile::Reader::kObjcRetainRelease;
-                                                       }
-                                                       else if ( sect->size() > 0 ) {
-                                                               warning("can't parse __OBJC/__image_info section in %s", fPath);
-                                                       }
-                                               }
-                                       }
-                               }
-               }
-
-               cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
-               if ( cmd > cmdsEnd )
-                       throwf("malformed dylb, load command #%d is outside size of load commands in %s", i, path);
-       }
-       
-       // Process the rest of the commands here.
-       cmd = cmds;
-       for (uint32_t i = 0; i < cmd_count; ++i) {
-               switch (cmd->cmd()) {
-               case LC_SUB_CLIENT:
-                       const char *temp = strdup(((macho_sub_client_command<P>*)cmd)->client());
-                       fAllowableClients.push_back(temp);
-                       break;
-               }
-               cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
-       }
-
-       // validate minimal load commands
-       if ( (fDylibInstallPath == NULL) && ((header->filetype() == MH_DYLIB) || (header->filetype() == MH_DYLIB_STUB)) ) 
-               throwf("dylib %s missing LC_ID_DYLIB load command", path);
-       if ( symbolTable == NULL )
-               throw "binary missing LC_SYMTAB load command";
-       if ( dynamicInfo == NULL )
-               throw "binary missing LC_DYSYMTAB load command";
-       
-       // if linking flat and this is a flat dylib, create one atom that references all imported symbols
-       if ( fLinkingFlat && fLinkingMainExecutable && ((header->flags() & MH_TWOLEVEL) == 0) ) {
-               std::vector<const char*> importNames;
-               importNames.reserve(dynamicInfo->nundefsym());
-               const macho_nlist<P>* start = &symbolTable[dynamicInfo->iundefsym()];
-               const macho_nlist<P>* end = &start[dynamicInfo->nundefsym()];
-               for (const macho_nlist<P>* sym=start; sym < end; ++sym) {
-                       importNames.push_back(&strings[sym->n_strx()]);
-               }
-               fFlatImports.push_back(new ImportAtom<A>(*this, fReExportedOrdinal++, importNames));
-       }
-       
-       // build hash table
-       if ( dyldInfo != NULL ) 
-               buildExportHashTableFromExportInfo(dyldInfo, fileContent);
-       else
-               buildExportHashTableFromSymbolTable(dynamicInfo, symbolTable, strings, fileContent);
-       
-       // special case libSystem
-       if ( (fDylibInstallPath != NULL) && (strcmp(fDylibInstallPath, "/usr/lib/libSystem.B.dylib") == 0) )
-               addDyldFastStub();
-       
-       // unmap file
-       munmap((caddr_t)fileContent, fileLength);
-}
-
-
-template <typename A>
-void Reader<A>::buildExportHashTableFromSymbolTable(const macho_dysymtab_command<P>* dynamicInfo, 
-                                                                                               const macho_nlist<P>* symbolTable, const char* strings, 
-                                                                                               const uint8_t* fileContent)
-{
-       if ( dynamicInfo->tocoff() == 0 ) {
-               if ( fgLogHashtable ) fprintf(stderr, "ld: building hashtable of %u toc entries for %s\n", dynamicInfo->nextdefsym(), this->getPath());
-               const macho_nlist<P>* start = &symbolTable[dynamicInfo->iextdefsym()];
-               const macho_nlist<P>* end = &start[dynamicInfo->nextdefsym()];
-               fAtoms.resize(dynamicInfo->nextdefsym()); // set initial bucket count
-               for (const macho_nlist<P>* sym=start; sym < end; ++sym) {
-                       this->addSymbol(&strings[sym->n_strx()], (sym->n_desc() & N_WEAK_DEF) != 0);
-               }
-       }
-       else {
-               int32_t count = dynamicInfo->ntoc();
-               fAtoms.resize(count); // set initial bucket count
-               if ( fgLogHashtable ) fprintf(stderr, "ld: building hashtable of %u entries for %s\n", count, this->getPath());
-               const struct dylib_table_of_contents* toc = (dylib_table_of_contents*)(fileContent + dynamicInfo->tocoff());
-               for (int32_t i = 0; i < count; ++i) {
-                       const uint32_t index = E::get32(toc[i].symbol_index);
-                       const macho_nlist<P>* sym = &symbolTable[index];
-                       this->addSymbol(&strings[sym->n_strx()], (sym->n_desc() & N_WEAK_DEF) != 0);
-               }
-       }
-}
-
-
-template <typename A>
-void Reader<A>::buildExportHashTableFromExportInfo(const macho_dyld_info_command<P>* dyldInfo, 
-                                                                                                                               const uint8_t* fileContent)
-{
-       if ( fgLogHashtable ) fprintf(stderr, "ld: building hashtable from export info in %s\n", this->getPath());
-       if ( dyldInfo->export_size() > 0 ) {
-               const uint8_t* start = fileContent + dyldInfo->export_off();
-               const uint8_t* end = &start[dyldInfo->export_size()];
-               std::vector<mach_o::trie::Entry> list;
-               parseTrie(start, end, list);
-               for (std::vector<mach_o::trie::Entry>::iterator it=list.begin(); it != list.end(); ++it) 
-                       this->addSymbol(it->name, it->flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
-       }
-}
-
-
-template <>
-void Reader<x86_64>::addDyldFastStub()
-{
-       addSymbol("dyld_stub_binder", false);
-}
-
-template <>
-void Reader<x86>::addDyldFastStub()
-{
-       addSymbol("dyld_stub_binder", false);
-}
-
-// hack for bring up of iPhoneOS builds on SnowLeopard
-template <>
-void Reader<arm>::addDyldFastStub()
-{
-       addSymbol("dyld_stub_binder", false);
-}
-
-template <typename A>
-void Reader<A>::addDyldFastStub()
-{
-       // do nothing
-}
-
-template <typename A>
-void Reader<A>::addSymbol(const char* name, bool weakDef)
-{
-       //fprintf(stderr, "addSymbol() %s\n", name);
-       // symbols that start with $ld$ are meta-data to the static linker
-       // <rdar://problem/5182537> need way for ld and dyld to see different exported symbols in a dylib
-       if ( strncmp(name, "$ld$", 4) == 0 ) {  
-               //    $ld$ <action> $ <condition> $ <symbol-name>
-               const char* symAction = &name[4];
-               const char* symCond = strchr(symAction, '$');
-               if ( symCond != NULL ) {
-                       if ( fMacDeploymentVersionMin != ObjectFile::ReaderOptions::kMinMacVersionUnset ) {
-                               ObjectFile::ReaderOptions::MacVersionMin symVersionCondition = ObjectFile::ReaderOptions::kMinMacVersionUnset;
-                               // ex:  $ld$add$os10.6$_foo
-                               if ( (strncmp(symCond, "$os10.", 6) == 0) && isdigit(symCond[6]) && (symCond[7] == '$') ) {
-                                       switch ( symCond[6] - '0' ) {
-                                               case 0:
-                                               case 1:
-                                                       symVersionCondition = ObjectFile::ReaderOptions::k10_1;
-                                                       break;
-                                               case 2:
-                                                       symVersionCondition = ObjectFile::ReaderOptions::k10_2;
-                                                       break;
-                                               case 3:
-                                                       symVersionCondition = ObjectFile::ReaderOptions::k10_3;
-                                                       break;
-                                               case 4:
-                                                       symVersionCondition = ObjectFile::ReaderOptions::k10_4;
-                                                       break;
-                                               case 5:
-                                                       symVersionCondition = ObjectFile::ReaderOptions::k10_5;
-                                                       break;
-                                               case 6:
-                                                       symVersionCondition = ObjectFile::ReaderOptions::k10_6;
-                                                       break;
-                                       }
-                                       const char* symName = strchr(&symCond[1], '$');
-                                       if ( symName != NULL ) {
-                                               ++symName;
-                                               if ( fMacDeploymentVersionMin == symVersionCondition ) {
-                                                       if ( strncmp(symAction, "hide$", 5) == 0 ) {
-                                                               if ( fgLogHashtable ) fprintf(stderr, "  adding %s to ignore set for %s\n", symName, this->getPath());
-                                                               fIgnoreExports.insert(strdup(symName));
-                                                               return;
-                                                       }
-                                                       else if ( strncmp(symAction, "add$", 4) == 0 ) {
-                                                               this->addSymbol(symName, weakDef);
-                                                               return;
-                                                       }
-                                                       else {
-                                                               warning("bad symbol action: %s in dylib %s", name, this->getPath());
-                                                       }
-                                               }
-                                       }
-                                       else {
-                                               warning("bad symbol name: %s in dylib %s", name, this->getPath());
-                                       }
-                               }
-                               else {
-                                       warning("bad symbol version: %s in dylib %s", name, this->getPath());
-                               }
-                       }
-                       else if ( fIPhoneDeploymentVersionMin != ObjectFile::ReaderOptions::kMinIPhoneVersionUnset ) {
-                               ObjectFile::ReaderOptions::IPhoneVersionMin symVersionCondition = ObjectFile::ReaderOptions::kMinIPhoneVersionUnset;
-                               // ex:  $ld$add$os3.1$_foo
-                               if ( (strncmp(symCond, "$os", 3) == 0) && isdigit(symCond[3]) && (symCond[4] == '.') ) {
-                                       if ( (symCond[3] == '2') && (symCond[5] == '0') )
-                                               symVersionCondition = ObjectFile::ReaderOptions::k2_0;
-                                       else if ( (symCond[3] == '2') && (symCond[5] == '1') )
-                                               symVersionCondition = ObjectFile::ReaderOptions::k2_1;
-                                       else if ( (symCond[3] == '2') && (symCond[5] >= '2') )
-                                               symVersionCondition = ObjectFile::ReaderOptions::k2_2;
-                                       else if ( (symCond[3] == '3') && (symCond[5] == '0') )
-                                               symVersionCondition = ObjectFile::ReaderOptions::k3_0;
-                                       else if ( (symCond[3] == '3') && (symCond[5] == '1') )
-                                               symVersionCondition = ObjectFile::ReaderOptions::k3_1;
-                                       else if ( (symCond[3] == '3') && (symCond[5] >= '2') )
-                                               symVersionCondition = ObjectFile::ReaderOptions::k3_2;
-                                       else if ( (symCond[3] >= '4')  )
-                                               symVersionCondition = ObjectFile::ReaderOptions::k4_0;
-                                       const char* symName = strchr(&symCond[1], '$');
-                                       if ( symName != NULL ) {
-                                               ++symName;
-                                               if ( fIPhoneDeploymentVersionMin == symVersionCondition ) {
-                                                       if ( strncmp(symAction, "hide$", 5) == 0 ) {
-                                                               if ( fgLogHashtable ) fprintf(stderr, "  adding %s to ignore set for %s\n", symName, this->getPath());
-                                                               fIgnoreExports.insert(strdup(symName));
-                                                               return;
-                                                       }
-                                                       else if ( strncmp(symAction, "add$", 4) == 0 ) {
-                                                               this->addSymbol(symName, weakDef);
-                                                               return;
-                                                       }
-                                                       else {
-                                                               warning("bad symbol action: %s in dylib %s", name, this->getPath());
-                                                       }
-                                               }
-                                       }
-                                       else {
-                                               warning("bad symbol name: %s in dylib %s", name, this->getPath());
-                                       }
-                               }
-                               else {
-                                       warning("bad symbol version: %s in dylib %s, symCond=%s", name, this->getPath(), symCond);
-                               }
-                       }
-               }       
-               else {
-                       warning("bad symbol condition: %s in dylib %s", name, this->getPath());
-               }
-       }
-       
-       // add symbol as possible export if we are not supposed to ignore it
-       if ( fIgnoreExports.count(name) == 0 ) {
-               AtomAndWeak bucket;
-               bucket.atom = NULL;
-               bucket.weak = weakDef;
-               bucket.ordinal = fReExportedOrdinal++;
-               if ( fgLogHashtable ) fprintf(stderr, "  adding %s to hash table for %s\n", name, this->getPath());
-               fAtoms[strdup(name)] = bucket;
-       }
-}
-
-
-template <typename A>
-std::vector<class ObjectFile::Atom*>& Reader<A>::getAtoms()
-{
-       return fFlatImports;
-}
-
-
-template <typename A>
-std::vector<class ObjectFile::Atom*>* Reader<A>::getJustInTimeAtomsFor(const char* name)
-{
-       // if supposed to ignore this export, then pretend I don't have it
-       if ( fIgnoreExports.count(name) != 0 )
-               return NULL;
-               
-       std::vector<class ObjectFile::Atom*>* atoms = NULL;
-       NameToAtomMapIterator pos = fAtoms.find(name);
-       if ( pos != fAtoms.end() ) {
-               if ( pos->second.atom == NULL ) {
-                       // instantiate atom and update hash table
-                       pos->second.atom = new ExportAtom<A>(*this, name, pos->second.weak, pos->second.ordinal);
-                       fProvidedAtom = true;
-                       if ( fgLogHashtable ) fprintf(stderr, "getJustInTimeAtomsFor: %s found in %s\n", name, this->getPath());
-               }
-               // return a vector of one atom
-               atoms = new std::vector<class ObjectFile::Atom*>;
-               atoms->push_back(pos->second.atom);
-       }
-       else {
-               if ( fgLogHashtable ) fprintf(stderr, "getJustInTimeAtomsFor: %s NOT found in %s\n", name, this->getPath());
-               // look in children that I re-export
-               for (std::vector<ObjectFile::Reader*>::iterator it = fReExportedChildren.begin(); it != fReExportedChildren.end(); it++) {
-                       //fprintf(stderr, "getJustInTimeAtomsFor: %s NOT found in %s, looking in child %s\n", name, this->getPath(), (*it)->getInstallPath());
-                       std::vector<class ObjectFile::Atom*>* childAtoms = (*it)->getJustInTimeAtomsFor(name);
-                       if ( childAtoms != NULL ) {
-                               // make a new atom that says this reader is the owner 
-                               bool isWeakDef = (childAtoms->at(0)->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition);
-                               // return a vector of one atom
-                               ExportAtom<A>* newAtom = new ExportAtom<A>(*this, name, isWeakDef, fReExportedOrdinal++);
-                               fProvidedAtom = true;
-                               atoms = new std::vector<class ObjectFile::Atom*>;
-                               atoms->push_back(newAtom);
-                               delete childAtoms;
-                               return atoms;
-                       }
-               }
-       }
-       return atoms;
-}
-
-
-
-template <typename A>
-bool Reader<A>::isPublicLocation(const char* path)
-{
-       // -no_implicit_dylibs disables this optimization
-       if ( ! fImplicitlyLinkPublicDylibs )
-               return false;
-       
-       // /usr/lib is a public location
-       if ( (strncmp(path, "/usr/lib/", 9) == 0) && (strchr(&path[9], '/') == NULL) )
-               return true;
-
-       // /System/Library/Frameworks/ is a public location
-       if ( strncmp(path, "/System/Library/Frameworks/", 27) == 0 ) {
-               const char* frameworkDot = strchr(&path[27], '.');
-               // but only top level framework
-               // /System/Library/Frameworks/Foo.framework/Versions/A/Foo                 ==> true
-               // /System/Library/Frameworks/Foo.framework/Resources/libBar.dylib         ==> false
-               // /System/Library/Frameworks/Foo.framework/Frameworks/Bar.framework/Bar   ==> false
-               // /System/Library/Frameworks/Foo.framework/Frameworks/Xfoo.framework/XFoo ==> false
-               if ( frameworkDot != NULL ) {
-                       int frameworkNameLen = frameworkDot - &path[27];
-                       if ( strncmp(&path[strlen(path)-frameworkNameLen-1], &path[26], frameworkNameLen+1) == 0 )
-                               return true;
-               }
-       }
-               
-       return false;
-}
-
-template <typename A>
-void Reader<A>::processIndirectLibraries(DylibHander* handler)
-{
-       if ( fLinkingFlat ) {
-               for (typename std::vector<PathAndFlag>::iterator it = fDependentLibraryPaths.begin(); it != fDependentLibraryPaths.end(); it++) {
-                       handler->findDylib(it->path, this->getPath());
-               }
-       }
-       else if ( fNoRexports ) {
-               // MH_NO_REEXPORTED_DYLIBS bit set, then nothing to do
-       }
-       else {
-               // two-level, might have re-exports
-               for (typename std::vector<PathAndFlag>::iterator it = fDependentLibraryPaths.begin(); it != fDependentLibraryPaths.end(); it++) {
-                       if ( it->reExport ) {
-                               //fprintf(stderr, "processIndirectLibraries() parent=%s, child=%s\n", this->getInstallPath(), it->path);
-                               // a LC_REEXPORT_DYLIB, LC_SUB_UMBRELLA or LC_SUB_LIBRARY says we re-export this child
-                               ObjectFile::Reader* child = handler->findDylib(it->path, this->getPath());
-                               if ( isPublicLocation(child->getInstallPath()) ) {
-                                       // promote this child to be automatically added as a direct dependent if this already is
-                                       if ( (this->explicitlyLinked() || this->implicitlyLinked()) && (strcmp(it->path,child->getInstallPath()) == 0) ) {
-                                               //fprintf(stderr, "processIndirectLibraries() implicitly linking %s\n", child->getInstallPath());
-                                               ((Reader<A>*)child)->setImplicitlyLinked();
-                                       }
-                                       else if ( child->explicitlyLinked() || child->implicitlyLinked() ) {
-                                               //fprintf(stderr, "processIndirectLibraries() parent is not directly linked, but child is, so no need to re-export child\n");
-                                       }
-                                       else {
-                                               fReExportedChildren.push_back(child);
-                                               //fprintf(stderr, "processIndirectLibraries() parent is not directly linked, so parent=%s will re-export child=%s\n", this->getInstallPath(), it->path);
-                                       }
-                               }
-                               else {
-                                       // add all child's symbols to me
-                                       fReExportedChildren.push_back(child);
-                                       //fprintf(stderr, "processIndirectLibraries() child is not public, so parent=%s will re-export child=%s\n", this->getInstallPath(), it->path);
-                               }
-                       }
-                       else if ( !fExplictReExportFound ) {
-                               // see if child contains LC_SUB_FRAMEWORK with my name
-                               ObjectFile::Reader* child = handler->findDylib(it->path, this->getPath());
-                               const char* parentUmbrellaName = ((Reader<A>*)child)->parentUmbrella();
-                               if ( parentUmbrellaName != NULL ) {
-                                       const char* parentName = this->getPath();
-                                       const char* lastSlash = strrchr(parentName, '/');
-                                       if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], parentUmbrellaName) == 0) ) {
-                                               // add all child's symbols to me
-                                               fReExportedChildren.push_back(child);
-                                               //fprintf(stderr, "processIndirectLibraries() umbrella=%s will re-export child=%s\n", this->getInstallPath(), it->path);
-                                       }
-                               }
-                       }
-               }
-       }
-       
-       // check for re-export cycles
-       ReExportChain chain;
-       chain.prev = NULL;
-       chain.reader = this;
-       this->assertNoReExportCycles(&chain);
-}
-
-template <typename A>
-void Reader<A>::assertNoReExportCycles(ReExportChain* prev)
-{
-       // recursively check my re-exported dylibs
-       ReExportChain chain;
-       chain.prev = prev;
-       chain.reader = this;
-       for (std::vector<ObjectFile::Reader*>::iterator it = fReExportedChildren.begin(); it != fReExportedChildren.end(); it++) {
-               ObjectFile::Reader* child = *it;
-               // check child is not already in chain 
-               for (ReExportChain* p = prev; p != NULL; p = p->prev) {
-                       if ( p->reader == child ) {
-                               throwf("cycle in dylib re-exports with %s", child->getPath());
-                       }
-               }
-               ((Reader<A>*)(*it))->assertNoReExportCycles(&chain);
-       }
-}
-
-
-template <typename A>
-std::vector<const char*>* Reader<A>::getAllowableClients()
-{
-       std::vector<const char*>* result = new std::vector<const char*>;
-       for (typename std::vector<const char*>::iterator it = fAllowableClients.begin();
-                it != fAllowableClients.end();
-                it++) {
-               result->push_back(*it);
-       }
-       return (fAllowableClients.size() != 0 ? result : NULL);
-}
-
-template <>
-bool Reader<ppc>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle)
-{
-       const macho_header<P>* header = (const macho_header<P>*)fileContent;
-       if ( header->magic() != MH_MAGIC )
-               return false;
-       if ( header->cputype() != CPU_TYPE_POWERPC )
-               return false;
-       switch ( header->filetype() ) {
-               case MH_DYLIB:
-               case MH_DYLIB_STUB:
-                       return true;
-               case MH_BUNDLE:
-                       if ( executableOrDyliborBundle )
-                               return true;
-                       else
-                               throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
-               case MH_EXECUTE:
-                       if ( executableOrDyliborBundle )
-                               return true;
-                       else
-                               throw "can't link with a main executable";
-               default:
-                       return false;
-       }
-}
-
-template <>
-bool Reader<ppc64>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle)
-{
-       const macho_header<P>* header = (const macho_header<P>*)fileContent;
-       if ( header->magic() != MH_MAGIC_64 )
-               return false;
-       if ( header->cputype() != CPU_TYPE_POWERPC64 )
-               return false;
-       switch ( header->filetype() ) {
-               case MH_DYLIB:
-               case MH_DYLIB_STUB:
-                       return true;
-               case MH_BUNDLE:
-                       if ( executableOrDyliborBundle )
-                               return true;
-                       else
-                               throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
-               case MH_EXECUTE:
-                       if ( executableOrDyliborBundle )
-                               return true;
-                       else
-                               throw "can't link with a main executable";
-               default:
-                       return false;
-       }
-}
-
-template <>
-bool Reader<x86>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle)
-{
-       const macho_header<P>* header = (const macho_header<P>*)fileContent;
-       if ( header->magic() != MH_MAGIC )
-               return false;
-       if ( header->cputype() != CPU_TYPE_I386 )
-               return false;
-       switch ( header->filetype() ) {
-               case MH_DYLIB:
-               case MH_DYLIB_STUB:
-                       return true;
-               case MH_BUNDLE:
-                       if ( executableOrDyliborBundle )
-                               return true;
-                       else
-                               throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
-               case MH_EXECUTE:
-                       if ( executableOrDyliborBundle )
-                               return true;
-                       else
-                               throw "can't link with a main executable";
-               default:
-                       return false;
-       }
-}
-
-template <>
-bool Reader<x86_64>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle)
-{
-       const macho_header<P>* header = (const macho_header<P>*)fileContent;
-       if ( header->magic() != MH_MAGIC_64 )
-               return false;
-       if ( header->cputype() != CPU_TYPE_X86_64 )
-               return false;
-       switch ( header->filetype() ) {
-               case MH_DYLIB:
-               case MH_DYLIB_STUB:
-                       return true;
-               case MH_BUNDLE:
-                       if ( executableOrDyliborBundle )
-                               return true;
-                       else
-                               throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
-               case MH_EXECUTE:
-                       if ( executableOrDyliborBundle )
-                               return true;
-                       else
-                               throw "can't link with a main executable";
-               default:
-                       return false;
-       }
-}
-
-template <>
-bool Reader<arm>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle)
-{
-       const macho_header<P>* header = (const macho_header<P>*)fileContent;
-       if ( header->magic() != MH_MAGIC )
-               return false;
-       if ( header->cputype() != CPU_TYPE_ARM )
-               return false;
-       switch ( header->filetype() ) {
-               case MH_DYLIB:
-               case MH_DYLIB_STUB:
-                       return true;
-               case MH_BUNDLE:
-                       if ( executableOrDyliborBundle )
-                               return true;
-                       else
-                               throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
-               case MH_EXECUTE:
-                       if ( executableOrDyliborBundle )
-                               return true;
-                       else
-                               throw "can't link with a main executable";
-               default:
-                       return false;
-       }
-}
-
-}; // namespace dylib
-}; // namespace mach_o
-
-
-#endif // __OBJECT_FILE_DYLIB_MACH_O__
diff --git a/src/ld/MachOReaderRelocatable.hpp b/src/ld/MachOReaderRelocatable.hpp
deleted file mode 100644 (file)
index 2aa7926..0000000
+++ /dev/null
@@ -1,6125 +0,0 @@
-/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
- *
- * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-#ifndef __OBJECT_FILE_MACH_O__
-#define __OBJECT_FILE_MACH_O__
-
-#include <stdint.h>
-#include <math.h>
-#include <unistd.h>
-#include <sys/param.h>
-
-#include <vector>
-#include <set>
-#include <algorithm>
-
-#include "MachOFileAbstraction.hpp"
-#include "Architectures.hpp"
-#include "ObjectFile.h"
-#include "dwarf2.h"
-#include "debugline.h"
-
-#include <libunwind/DwarfInstructions.hpp>
-#include <libunwind/AddressSpace.hpp>
-#include <libunwind/Registers.hpp>
-
-//
-//
-//     To implement architecture xxx, you must write template specializations for the following six methods:
-//                     Reader<xxx>::validFile()
-//                     Reader<xxx>::validSectionType()
-//                     Reader<xxx>::addRelocReference()
-//                     Reference<xxx>::getDescription()
-//
-//
-
-
-
-extern  __attribute__((noreturn)) void throwf(const char* format, ...);
-extern void warning(const char* format, ...);
-
-namespace mach_o {
-namespace relocatable {
-
-
-
-class ReferenceSorter
-{
-public:
-       bool operator()(const ObjectFile::Reference* left, const ObjectFile::Reference* right)
-       {
-               return ( left->getFixUpOffset() < right->getFixUpOffset() );
-       }
-};
-
-
-// forward reference
-template <typename A> class Reader;
-
-struct AtomAndOffset
-{
-                                               AtomAndOffset(ObjectFile::Atom* a=NULL) : atom(a), offset(0) {}
-                                               AtomAndOffset(ObjectFile::Atom* a, uint32_t off) : atom(a), offset(off) {}
-       ObjectFile::Atom*       atom;
-       uint32_t                        offset;
-};
-
-
-template <typename A>
-class Reference : public ObjectFile::Reference
-{
-public:
-       typedef typename A::P                                           P;
-       typedef typename A::P::uint_t                           pint_t;
-       typedef typename A::ReferenceKinds                      Kinds;
-
-                                                       Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& toTarget);
-                                                       Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& fromTarget, const AtomAndOffset& toTarget);
-                                                       Reference(Kinds kind, const AtomAndOffset& at, const char* toName, uint32_t toOffset);
-
-       virtual                                 ~Reference() {}
-
-
-       virtual ObjectFile::Reference::TargetBinding    getTargetBinding() const;
-       virtual ObjectFile::Reference::TargetBinding    getFromTargetBinding() const;
-       virtual uint8_t                 getKind() const                                                                 { return (uint8_t)fKind; }
-       virtual uint64_t                getFixUpOffset() const                                                  { return fFixUpOffsetInSrc; }
-       virtual const char*             getTargetName() const                                                   { return (fToTarget.atom != NULL) ? fToTarget.atom->getName() : fToTargetName;  }
-       virtual ObjectFile::Atom& getTarget() const                                                             { return *fToTarget.atom; }
-       virtual uint64_t                getTargetOffset() const                                                 { return (int64_t)((int32_t)fToTarget.offset); }
-       virtual ObjectFile::Atom& getFromTarget() const                                                 { return *fFromTarget.atom; }
-       virtual const char*             getFromTargetName() const                                               { return (fFromTarget.atom != NULL) ? fFromTarget.atom->getName() : fFromTargetName; }
-       virtual void                    setTarget(ObjectFile::Atom& target, uint64_t offset)    { fToTarget.atom = &target; fToTarget.offset = offset;  }
-       virtual void                    setToTargetOffset(uint64_t offset)                              { fToTarget.offset = offset; }
-       virtual void                    setFromTarget(ObjectFile::Atom& target)                 { fFromTarget.atom = &target; }
-       virtual void                    setFromTargetName(const char* name)                             { fFromTargetName = name; }
-       virtual void                    setFromTargetOffset(uint64_t offset)                    { fFromTarget.offset = offset; }
-       virtual const char*             getDescription() const;
-       virtual uint64_t                getFromTargetOffset() const                                             { return fFromTarget.offset; }
-       virtual bool                    isBranch() const;
-       virtual const char*             getTargetDisplayName() const                                    { return (fToTarget.atom != NULL) ? fToTarget.atom->getDisplayName() : fToTargetName;  }
-       virtual const char*             getFromTargetDisplayName() const                                { return (fFromTarget.atom != NULL) ? fFromTarget.atom->getDisplayName() : fFromTargetName; }
-
-       static bool                             fgForFinalLinkedImage;
-
-private:
-       pint_t                                  fFixUpOffsetInSrc;
-       AtomAndOffset                   fToTarget;
-       AtomAndOffset                   fFromTarget;
-       const char*                             fToTargetName;
-       const char*                             fFromTargetName;
-       Kinds                                   fKind;
-       
-};
-
-
-template <typename A> bool Reference<A>::fgForFinalLinkedImage = true;
-
-template <typename A>
-Reference<A>::Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& toTarget)
- : fFixUpOffsetInSrc(at.offset), fToTarget(toTarget), fToTargetName(NULL), fFromTargetName(NULL),
-    fKind(kind)
-{
-       // make reference a by-name unless:
-       // - the reference type is only used with direct references
-       // - the target is translation unit scoped
-       // - the target kind is not regular (is weak or tentative)
-       if ( (kind != A::kNoFixUp) && (kind != A::kFollowOn) && (kind != A::kGroupSubordinate)
-               && (toTarget.atom->getScope() != ObjectFile::Atom::scopeTranslationUnit) 
-               && (toTarget.atom->getDefinitionKind() != ObjectFile::Atom::kRegularDefinition)
-               && (toTarget.atom != at.atom) ) {
-               fToTargetName = toTarget.atom->getName();
-               //fprintf(stderr, "Reference(): changing to by-name %p %s, target scope=%d, target section=%s\n", toTarget.atom, fToTargetName, toTarget.atom->getScope(), toTarget.atom->getSectionName());
-               fToTarget.atom = NULL;
-       }
-       ((class BaseAtom*)at.atom)->addReference(this);
-       //fprintf(stderr, "Reference(): %p fToTarget<%s, %08X>\n", this, (fToTarget.atom != NULL) ? fToTarget.atom->getDisplayName() : fToTargetName , fToTarget.offset);
-}
-
-template <typename A>
-Reference<A>::Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset& fromTarget, const AtomAndOffset& toTarget)
- : fFixUpOffsetInSrc(at.offset), fToTarget(toTarget), fFromTarget(fromTarget),
-   fToTargetName(NULL), fFromTargetName(NULL), fKind(kind)
-{
-       // make reference a by-name where needed
-       if ( (kind != A::kNoFixUp) && (kind != A::kFollowOn) && (kind != A::kGroupSubordinate)
-               && (toTarget.atom->getScope() != ObjectFile::Atom::scopeTranslationUnit)
-               && (toTarget.atom->getDefinitionKind() != ObjectFile::Atom::kRegularDefinition) 
-               && (toTarget.atom != at.atom) ) {
-                       fToTargetName = toTarget.atom->getName();
-                       fToTarget.atom = NULL;
-       }
-       ((class BaseAtom*)at.atom)->addReference(this);
-       //fprintf(stderr, "Reference(): %p kind=%d, fToTarget<%s, %08X>, fromTarget<%s, %08X>\n", this, kind,
-       //       this->getTargetName(), fToTarget.offset, this->getFromTargetName(), fromTarget.offset);
-}
-
-template <typename A>
-Reference<A>::Reference(Kinds kind, const AtomAndOffset& at, const char* toName, uint32_t toOffset)
- : fFixUpOffsetInSrc(at.offset),
-   fToTargetName(toName), fFromTargetName(NULL), fKind(kind)
-{
-       fToTarget.offset = toOffset;
-       ((class BaseAtom*)at.atom)->addReference(this);
-}
-
-template <typename A>
-ObjectFile::Reference::TargetBinding Reference<A>::getTargetBinding() const
-{
-       if ( fgForFinalLinkedImage ) {
-               if ( (fKind == A::kDtraceProbe) || (fKind == A::kDtraceProbeSite) || (fKind == A::kDtraceIsEnabledSite) || (fKind == A::kDtraceTypeReference) )
-                       return ObjectFile::Reference::kDontBind;
-       }
-       if ( fToTarget.atom == NULL ) 
-               return ObjectFile::Reference::kUnboundByName;
-       if ( fToTargetName == NULL ) 
-               return ObjectFile::Reference::kBoundDirectly;
-       else
-               return ObjectFile::Reference::kBoundByName;
-}
-
-template <typename A>
-ObjectFile::Reference::TargetBinding Reference<A>::getFromTargetBinding() const
-{
-       if ( fFromTarget.atom == NULL ) {
-               if ( fFromTargetName == NULL ) 
-                       return ObjectFile::Reference::kDontBind;
-               else
-                       return ObjectFile::Reference::kUnboundByName;
-       }
-       else {
-               if ( fFromTargetName == NULL ) 
-                       return ObjectFile::Reference::kBoundDirectly;
-               else
-                       return ObjectFile::Reference::kBoundByName;
-       }
-}
-
-
-
-template <typename A>
-class Segment : public ObjectFile::Segment
-{
-public:
-                                                               Segment(const macho_section<typename A::P>* sect);
-       virtual const char*                     getName() const                                         { return fSection->segname(); }
-       virtual bool                            isContentReadable() const                       { return true; }
-       virtual bool                            isContentWritable() const                       { return fWritable; }
-       virtual bool                            isContentExecutable() const                     { return fExecutable; }
-private:
-       const macho_section<typename A::P>*             fSection;
-       bool                                                                    fWritable;
-       bool                                                                    fExecutable;
-};
-
-template <typename A>
-Segment<A>::Segment(const macho_section<typename A::P>* sect) 
- :     fSection(sect), fWritable(true),  fExecutable(false) 
-{
-       if ( strcmp(fSection->segname(), "__TEXT") == 0 ) {
-               fWritable = false;
-               fExecutable = true;
-       }
-       else if ( strcmp(fSection->segname(), "__IMPORT") == 0 ) {
-               fWritable = true;
-               fExecutable = true;
-       }
-}
-
-
-class DataSegment : public ObjectFile::Segment
-{
-public:
-       virtual const char*                     getName() const                                         { return "__DATA"; }
-       virtual bool                            isContentReadable() const                       { return true; }
-       virtual bool                            isContentWritable() const                       { return true; }
-       virtual bool                            isContentExecutable() const                     { return false; }
-
-       static DataSegment                      fgSingleton;
-};
-
-DataSegment DataSegment::fgSingleton;
-
-class LinkEditSegment : public ObjectFile::Segment
-{
-public:
-       virtual const char*                     getName() const                                         { return "__LINKEDIT"; }
-       virtual bool                            isContentReadable() const                       { return true; }
-       virtual bool                            isContentWritable() const                       { return false; }
-       virtual bool                            isContentExecutable() const                     { return false; }
-
-       static LinkEditSegment                  fgSingleton;
-};
-
-LinkEditSegment LinkEditSegment::fgSingleton;
-
-class BaseAtom : public ObjectFile::Atom
-{
-public:
-                                                                                               BaseAtom() : fStabsStartIndex(0), fStabsCount(0), fHasCompactUnwindInfo(false) {}
-
-       virtual void                                                            setSize(uint64_t size) = 0;
-       virtual void                                                            addReference(ObjectFile::Reference* ref) = 0;
-       virtual void                                                            sortReferences() = 0;
-       virtual void                                                            addLineInfo(const ObjectFile::LineInfo& info) = 0;
-       virtual const ObjectFile::ReaderOptions&        getOptions() const = 0;
-       virtual uint64_t                                                        getObjectAddress() const = 0;
-       virtual uint32_t                                                        getOrdinal() const { return fOrdinal; }
-       virtual void                                                            setOrdinal(uint32_t value) { fOrdinal = value; }
-       virtual const void*                                                     getSectionRecord() const = 0;
-       virtual unsigned int                                            getSectionIndex() const = 0;
-       virtual bool                                                            isAlias() const { return false; }
-       virtual uint8_t                                                         getLSDAReferenceKind() const { return 0; }
-       virtual uint8_t                                                         getPersonalityReferenceKind() const { return 0; }
-       virtual uint32_t                                                        getCompactUnwindEncoding(uint64_t ehAtomAddress) { return 0; }
-       virtual ObjectFile::UnwindInfo::iterator        beginUnwind()                                   { return fHasCompactUnwindInfo ? &fSingleUnwindInfo[0] : NULL; }
-       virtual ObjectFile::UnwindInfo::iterator        endUnwind()                                             { return fHasCompactUnwindInfo ? &fSingleUnwindInfo[1] : NULL; }
-       virtual ObjectFile::Reference*                          getLSDA();
-       virtual ObjectFile::Reference*                          getFDE();
-       virtual Atom*                                                           getPersonalityPointer();
-       virtual void                                                            setCompactUnwindEncoding(uint64_t ehAtomAddress);
-
-       uint32_t                                                                        fStabsStartIndex;
-       uint32_t                                                                        fStabsCount;
-       uint32_t                                                                        fOrdinal;
-       ObjectFile::UnwindInfo                                          fSingleUnwindInfo[1];
-       bool                                                                            fHasCompactUnwindInfo;
-};
-
-
-ObjectFile::Reference* BaseAtom::getLSDA()
-{
-       const uint8_t groupKind = this->getLSDAReferenceKind(); 
-       const std::vector<ObjectFile::Reference*>& refs = this->getReferences();
-       for (std::vector<ObjectFile::Reference*>::const_iterator it=refs.begin(); it != refs.end(); it++) {
-               ObjectFile::Reference* ref = *it;
-               if ( (ref->getKind() == groupKind) && (ref->getTarget().getContentType() == ObjectFile::Atom::kLSDAType) ) {
-                       return ref;
-               }
-       }
-       return NULL;
-}
-
-ObjectFile::Reference* BaseAtom::getFDE()
-{
-       const uint8_t groupKind = this->getLSDAReferenceKind(); 
-       const std::vector<ObjectFile::Reference*>& refs = this->getReferences();
-       for (std::vector<ObjectFile::Reference*>::const_iterator it=refs.begin(); it != refs.end(); it++) {
-               ObjectFile::Reference* ref = *it;
-               if ( (ref->getKind() == groupKind) && (ref->getTarget().getContentType() == ObjectFile::Atom::kCFIType) ) {
-                       return ref;
-               }
-       }
-       return NULL;
-}
-
-ObjectFile::Atom* BaseAtom::getPersonalityPointer()
-{
-       const uint8_t personalityKind = this->getPersonalityReferenceKind(); 
-       const std::vector<ObjectFile::Reference*>& refs = this->getReferences();
-       for (std::vector<ObjectFile::Reference*>::const_iterator it=refs.begin(); it != refs.end(); it++) {
-               ObjectFile::Reference* ref = *it;
-               if ( ref->getKind() == personalityKind ) {
-                       if ( strcmp(ref->getTarget().getSectionName(), "__nl_symbol_ptr") == 0 )
-                               return &ref->getTarget();
-                       if ( strcmp(ref->getTarget().getSectionName(), "__pointers") == 0 )
-                               return &ref->getTarget();
-               }
-       }
-       return NULL;
-}
-
-
-void BaseAtom::setCompactUnwindEncoding(uint64_t ehAtomAddress)
-{
-       fSingleUnwindInfo[0].unwindInfo = this->getCompactUnwindEncoding(ehAtomAddress);
-       fHasCompactUnwindInfo = true;
-}
-
-
-class BaseAtomSorter
-{
-public:
-       bool operator()(const class BaseAtom* left, const class BaseAtom* right)  {
-               if ( left == right )
-                       return false;
-               uint64_t leftAddr  =  left->getObjectAddress();
-               uint64_t rightAddr = right->getObjectAddress();
-               if ( leftAddr < rightAddr ) {
-                       return true;
-               }
-               else if ( leftAddr > rightAddr ) {
-                       return false;
-               }
-               else {
-                       // if they have same address, one might be the end of a section and the other the start of the next section
-                       const void* leftSection  =  left->getSectionRecord();
-                       const void* rightSection =  right->getSectionRecord();
-                       if ( leftSection != rightSection ) {
-                               return ( leftSection < rightSection );
-                       }
-                       // if they have same address and section, one might be an alias
-                       bool leftAlias  = left->isAlias();
-                       bool rightAlias = right->isAlias();
-                       if ( leftAlias && rightAlias ) {
-                               // sort multiple aliases for same address first by scope
-                               ObjectFile::Atom::Scope leftScope  = left->getScope();
-                               ObjectFile::Atom::Scope rightScope = right->getScope();
-                               if ( leftScope != rightScope ) {
-                                       return ( leftScope < rightScope );
-                               }
-                               // sort multiple aliases for same address then by name
-                               return ( strcmp(left->getName(), right->getName()) < 0 );
-                       }
-                       else if ( leftAlias ) {
-                               return true;
-                       }
-                       else if ( rightAlias ) {
-                               return false;
-                       }
-                       // one might be a section start or end label
-                       switch ( left->getContentType() ) {
-                               case ObjectFile::Atom::kSectionStart:
-                                       return true;
-                               case ObjectFile::Atom::kSectionEnd:
-                                       return false;
-                               default:
-                                       break;
-                       }
-                       switch ( right->getContentType() ) {
-                               case ObjectFile::Atom::kSectionStart:
-                                       return false;
-                               case ObjectFile::Atom::kSectionEnd:
-                                       return true;
-                               default:
-                                       break;
-                       }
-                       // they could be tentative defintions
-                       switch ( left->getDefinitionKind() ) {
-                               case ObjectFile::Atom::kTentativeDefinition:
-                                       // sort tentative definitions by name
-                                       return ( strcmp(left->getName(), right->getName()) < 0 );
-                               case ObjectFile::Atom::kAbsoluteSymbol:
-                                       // sort absolute symbols with same address by name
-                                       return ( strcmp(left->getName(), right->getName()) < 0 );
-                               default:
-                                       // hack for rdar://problem/5102873
-                                       if ( !left->isZeroFill() || !right->isZeroFill() )
-                                               warning("atom sorting error for %s and %s in %s", left->getDisplayName(), right->getDisplayName(), left->getFile()->getPath());
-                                       break;
-                       }
-               }
-               return false;
-       }
-};
-
-
-//
-// A SymbolAtom represents a chunk of a mach-o object file that has a symbol table entry
-// pointing to it.  A C function or global variable is represented by one of these atoms.
-//
-//
-template <typename A>
-class SymbolAtom : public BaseAtom
-{
-public:
-       virtual ObjectFile::Reader*                                     getFile() const                                 { return &fOwner; }
-       virtual bool                                                            getTranslationUnitSource(const char** dir, const char** name) const
-                                                                                                                                                               { return fOwner.getTranslationUnitSource(dir, name); }
-       virtual const char*                                                     getName() const                                 { return &fOwner.fStrings[fSymbol->n_strx()]; }
-       virtual const char*                                                     getDisplayName() const                  { return getName(); }
-       virtual ObjectFile::Atom::Scope                         getScope() const                                { return fScope; }
-       virtual ObjectFile::Atom::DefinitionKind        getDefinitionKind() const               { return ((fSymbol->n_desc() & N_WEAK_DEF) != 0)
-                                                                                                                                                                               ? ObjectFile::Atom::kWeakDefinition : ObjectFile::Atom::kRegularDefinition; }
-       virtual ObjectFile::Atom::ContentType           getContentType() const                  { return fType; }
-       virtual SymbolTableInclusion                            getSymbolTableInclusion() const { return fSymbolTableInclusion; }
-       virtual bool                                                            dontDeadStrip() const;
-       virtual bool                                                            isZeroFill() const;
-       virtual bool                                                            isThumb() const                                 { return ((fSymbol->n_desc() & N_ARM_THUMB_DEF) != 0); }
-       virtual uint64_t                                                        getSize() const                                 { return fSize; }
-       virtual std::vector<ObjectFile::Reference*>&  getReferences() const                     { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
-       virtual bool                                                            mustRemainInSection() const             { return true; }
-       virtual const char*                                                     getSectionName() const;
-       virtual Segment<A>&                                                     getSegment() const                              { return *fSegment; }
-       virtual ObjectFile::Atom&                                       getFollowOnAtom() const;
-       virtual std::vector<ObjectFile::LineInfo>*      getLineInfo() const                             { return (std::vector<ObjectFile::LineInfo>*)&fLineInfo; }
-       virtual ObjectFile::Alignment                           getAlignment() const                    { return fAlignment; }
-       virtual void                                                            copyRawContent(uint8_t buffer[]) const;
-       virtual void                                                            setScope(ObjectFile::Atom::Scope newScope)              { fScope = newScope; }
-       virtual void                                                            setSize(uint64_t size);
-       virtual void                                                            addReference(ObjectFile::Reference* ref) { fReferences.push_back((Reference<A>*)ref); }
-       virtual void                                                            sortReferences() { std::sort(fReferences.begin(), fReferences.end(), ReferenceSorter()); }
-       virtual void                                                            addLineInfo(const  ObjectFile::LineInfo& info)  { fLineInfo.push_back(info); }
-       virtual const ObjectFile::ReaderOptions&        getOptions() const                              { return fOwner.fOptions; }
-       virtual uint64_t                                                        getObjectAddress() const                { return fAddress; }
-       virtual const void*                                                     getSectionRecord() const                { return (const void*)fSection; }
-       virtual unsigned int                                            getSectionIndex() const                 { return 1 + (fSection - fOwner.fSectionsStart); }
-       virtual uint8_t                                                         getLSDAReferenceKind() const;
-       virtual uint8_t                                                         getPersonalityReferenceKind() const;
-       virtual uint32_t                                                        getCompactUnwindEncoding(uint64_t ehAtomAddress);
-
-protected:
-       typedef typename A::P                                           P;
-       typedef typename A::P::E                                        E;
-       typedef typename A::P::uint_t                           pint_t;
-       typedef typename A::ReferenceKinds                      Kinds;
-       typedef typename std::vector<Reference<A>*>                     ReferenceVector;
-       typedef typename ReferenceVector::iterator                      ReferenceVectorIterator;                // seems to help C++ parser
-       typedef typename ReferenceVector::const_iterator        ReferenceVectorConstIterator;   // seems to help C++ parser
-       friend class Reader<A>;
-
-                                                                                       SymbolAtom(Reader<A>&, const macho_nlist<P>*, const macho_section<P>*);
-       virtual                                                                 ~SymbolAtom() {}
-
-       Reader<A>&                                                                      fOwner;
-       const macho_nlist<P>*                                           fSymbol;
-       pint_t                                                                          fAddress;
-       pint_t                                                                          fSize;
-       const macho_section<P>*                                         fSection;
-       Segment<A>*                                                                     fSegment;
-       ReferenceVector                                                         fReferences;
-       std::vector<ObjectFile::LineInfo>                       fLineInfo;
-       ObjectFile::Atom::Scope                                         fScope;
-       SymbolTableInclusion                                            fSymbolTableInclusion;
-       ObjectFile::Atom::ContentType                           fType;
-       ObjectFile::Alignment                                           fAlignment;
-};
-
-
-template <typename A>
-SymbolAtom<A>::SymbolAtom(Reader<A>& owner, const macho_nlist<P>* symbol, const macho_section<P>* section)
- : fOwner(owner), fSymbol(symbol), fAddress(0), fSize(0), fSection(section), fSegment(NULL), fType(ObjectFile::Atom::kUnclassifiedType), fAlignment(0)
-{
-    fSingleUnwindInfo[0].startOffset = 0;
-       fSingleUnwindInfo[0].unwindInfo = 0;
-       uint8_t type =  symbol->n_type();
-       if ( (type & N_EXT) == 0 )
-               fScope = ObjectFile::Atom::scopeTranslationUnit;
-       else if ( (type & N_PEXT) != 0 )
-               fScope = ObjectFile::Atom::scopeLinkageUnit;
-       else
-               fScope = ObjectFile::Atom::scopeGlobal;
-       if ( (type & N_TYPE) == N_SECT ) {
-               // real definition
-               fSegment = new Segment<A>(fSection);
-               fAddress = fSymbol->n_value();
-               pint_t sectionStartAddr = section->addr();
-               pint_t sectionEndAddr = section->addr()+section->size();
-               if ( (fAddress < sectionStartAddr) || (fAddress > (sectionEndAddr)) ) {
-                       throwf("malformed .o file, symbol %s with address 0x%0llX is not with section %d (%s,%s) address range of 0x%0llX to 0x%0llX",
-                               this->getName(), (uint64_t)fAddress, fSymbol->n_sect(), section->segname(), section->sectname(), 
-                               (uint64_t)sectionStartAddr, (uint64_t)(sectionEndAddr) );
-               }
-       }       
-       else {
-               warning("unknown symbol type: %d", type);
-       }
-       
-       //fprintf(stderr, "SymbolAtom(%p) %s fAddress=0x%X\n", this, this->getDisplayName(), (uint32_t)fAddress);
-       // support for .o files built with old ld64
-       if ( (fSymbol->n_desc() & N_WEAK_DEF) && (strcmp(fSection->sectname(),"__picsymbolstub1__TEXT") == 0) ) {
-               const char* name = this->getName();
-               const int nameLen = strlen(name);
-               if ( (nameLen > 6) && strcmp(&name[nameLen-5], "$stub") == 0 ) {
-                       // switch symbol to point at name that does not have trailing $stub
-                       char correctName[nameLen];
-                       strncpy(correctName, name, nameLen-5);
-                       correctName[nameLen-5] = '\0';
-                       const macho_nlist<P>* symbolsStart = fOwner.fSymbols;
-                       const macho_nlist<P>* symbolsEnd = &symbolsStart[fOwner.fSymbolCount];
-                       for(const macho_nlist<P>* s = symbolsStart; s < symbolsEnd; ++s) {
-                               if ( strcmp(&fOwner.fStrings[s->n_strx()], correctName) == 0 ) {
-                                       fSymbol = s;
-                                       break;
-                               }
-                       }
-               }
-       }
-       // support for labeled stubs
-       switch ( section->flags() & SECTION_TYPE ) {
-               case S_SYMBOL_STUBS:
-                       setSize(section->reserved2());
-                       break;
-               case S_LAZY_SYMBOL_POINTERS:
-               case S_NON_LAZY_SYMBOL_POINTERS:
-                       setSize(sizeof(pint_t));
-                       break;
-               case S_4BYTE_LITERALS:
-                       setSize(4);
-                       break;
-               case S_8BYTE_LITERALS:
-                       setSize(8);
-                       break;
-               case S_16BYTE_LITERALS:
-                       setSize(16);
-                       break;
-               case S_CSTRING_LITERALS:
-                       setSize(strlen((char*)(fOwner.fHeader) + section->offset() + fAddress - section->addr()) + 1);
-                       fType = ObjectFile::Atom::kCStringType;
-                       break;
-               case S_REGULAR:
-               case S_ZEROFILL:
-               case S_COALESCED:
-                       // size calculate later after next atom is found
-                       break;
-       }
-       
-       // compute alignment
-       fAlignment = ObjectFile::Alignment(fSection->align(), fAddress % (1 << fSection->align()));
-
-       // compute whether this atom needs to be in symbol table
-       if ( (fSymbol->n_desc() & REFERENCED_DYNAMICALLY) != 0) {
-               fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableInAndNeverStrip;
-       }
-       else if ( fOwner.fOptions.fForFinalLinkedImage && !fOwner.fOptions.fForStatic && (fOwner.fStrings[fSymbol->n_strx()] == 'l') ) {
-               // labels beginning with a lowercase ell are automatically removed in final linked images <rdar://problem/4571042>
-               // xnu code base uses a lot of asesembly labels that start with 'l', don't strip those (static executable)
-               fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableNotIn;
-       }
-       else {
-               fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
-       }
-       
-       // work around malformed icc generated .o files  <rdar://problem/5349847>
-       // if section starts with a symbol and that symbol address does not match section alignment, then force it to
-       if ( (section->addr() == fAddress) && (fAlignment.modulus != 0) )
-               fAlignment.modulus = 0;
-}
-
-
-template <typename A>
-bool SymbolAtom<A>::dontDeadStrip() const
-{
-       // the symbol can have a no-dead-strip bit
-       if ( (fSymbol->n_desc() & (N_NO_DEAD_STRIP|REFERENCED_DYNAMICALLY)) != 0 )
-               return true;
-       // or the section can have a no-dead-strip bit
-       return ( fSection->flags() & S_ATTR_NO_DEAD_STRIP );
-}
-
-
-template <typename A>
-const char*    SymbolAtom<A>::getSectionName() const
-{
-       if ( fOwner.fOptions.fForFinalLinkedImage ) {
-               if ( strcmp(fSection->sectname(), "__textcoal_nt") == 0 )
-                       return "__text";
-               else if ( strcmp(fSection->sectname(), "__const_coal") == 0 )
-                       return "__const";
-               else if ( strcmp(fSection->sectname(), "__datacoal_nt") == 0 )
-                       return "__data";
-               else if ( fOwner.fOptions.fAutoOrderInitializers && (strcmp(fSection->sectname(), "__StaticInit") == 0) )
-                       return "__text";
-               else {
-                       switch ( fSection->flags() & SECTION_TYPE ) {
-                               case S_4BYTE_LITERALS:
-                               case S_8BYTE_LITERALS:
-                               case S_16BYTE_LITERALS:
-                                       return "__const";
-                       }
-               }
-       }
-       
-       if ( strlen(fSection->sectname()) > 15 ) {
-               static char temp[18];
-               strncpy(temp, fSection->sectname(), 16);
-               temp[17] = '\0';
-               return temp;
-       }
-       return fSection->sectname();
-}
-
-template <typename A>
-ObjectFile::Atom& SymbolAtom<A>::getFollowOnAtom() const
-{
-       for (ReferenceVectorConstIterator it=fReferences.begin(); it != fReferences.end(); it++) {
-               Reference<A>* ref = *it;
-               if ( ref->getKind() == A::kFollowOn )
-                       return ref->getTarget();
-       }
-       return *((ObjectFile::Atom*)NULL);
-}
-
-template <typename A>
-bool SymbolAtom<A>::isZeroFill() const
-{
-       return ( ((fSection->flags() & SECTION_TYPE) == S_ZEROFILL) && fOwner.fOptions.fOptimizeZeroFill );
-}
-
-
-class Beyond
-{
-public:
-       Beyond(uint64_t offset) : fOffset(offset) {}
-       bool operator()(ObjectFile::Reference* ref) const {
-               return ( ref->getFixUpOffset() >= fOffset );
-       }
-private:
-       uint64_t fOffset;
-};
-
-
-template <typename A>
-void SymbolAtom<A>::setSize(uint64_t size)
-{
-       // when resizing, any references beyond the new size are tossed
-       if ( (fSize != 0) && (fReferences.size() > 0) ) 
-               fReferences.erase(std::remove_if(fReferences.begin(), fReferences.end(), Beyond(size)), fReferences.end());
-       // set new size
-       fSize = size;
-}
-
-template <typename A>
-void SymbolAtom<A>::copyRawContent(uint8_t buffer[]) const
-{
-       // copy base bytes
-       if ( isZeroFill() )
-               bzero(buffer, fSize);
-       else {
-               uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
-               memcpy(buffer, (char*)(fOwner.fHeader)+fileOffset, fSize);
-       }
-}
-
-
-
-
-//
-// A SymbolAliasAtom represents an alternate name for a SymbolAtom
-//
-//
-template <typename A>
-class SymbolAliasAtom : public BaseAtom
-{
-public:
-       virtual ObjectFile::Reader*                                     getFile() const                                 { return fAliasOf.getFile(); }
-       virtual bool                                                            getTranslationUnitSource(const char** dir, const char** name) const
-                                                                                                                                                               { return fAliasOf.getTranslationUnitSource(dir, name); }
-       virtual const char*                                                     getName() const                                 { return fName; }
-       virtual const char*                                                     getDisplayName() const                  { return fName; }
-       virtual ObjectFile::Atom::Scope                         getScope() const                                { return fScope; }
-       virtual ObjectFile::Atom::DefinitionKind        getDefinitionKind() const               { return fAliasOf.getDefinitionKind(); }
-       virtual SymbolTableInclusion                            getSymbolTableInclusion() const { return fAliasOf.getSymbolTableInclusion(); }
-       virtual bool                                                            dontDeadStrip() const                   { return fDontDeadStrip; }
-       virtual bool                                                            isZeroFill() const                              { return fAliasOf.isZeroFill(); }
-       virtual bool                                                            isThumb() const                                 { return fAliasOf.isThumb(); }
-       virtual uint64_t                                                        getSize() const                                 { return 0; }
-       virtual std::vector<ObjectFile::Reference*>&  getReferences() const                     { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
-       virtual bool                                                            mustRemainInSection() const             { return true; }
-       virtual const char*                                                     getSectionName() const                  { return fAliasOf.getSectionName(); }
-       virtual Segment<A>&                                                     getSegment() const                              { return (Segment<A>&)fAliasOf.getSegment(); }
-       virtual ObjectFile::Atom&                                       getFollowOnAtom() const                 { return (ObjectFile::Atom&)fAliasOf; }
-       virtual std::vector<ObjectFile::LineInfo>*      getLineInfo() const                             { return NULL; }
-       virtual ObjectFile::Alignment                           getAlignment() const                    { return  fAliasOf.getAlignment(); }
-       virtual void                                                            copyRawContent(uint8_t buffer[]) const {}
-       virtual void                                                            setScope(ObjectFile::Atom::Scope newScope)              { fScope = newScope; }
-       virtual void                                                            setSize(uint64_t size)                  {  }
-       virtual void                                                            addReference(ObjectFile::Reference* ref) { fReferences.push_back((Reference<A>*)ref); }
-       virtual void                                                            sortReferences() { std::sort(fReferences.begin(), fReferences.end(), ReferenceSorter()); }
-       virtual void                                                            addLineInfo(const  ObjectFile::LineInfo& info)  {  }
-       virtual const ObjectFile::ReaderOptions&        getOptions() const                              { return fAliasOf.getOptions(); }
-       virtual uint64_t                                                        getObjectAddress() const                { return fAliasOf.getObjectAddress(); }
-       virtual const void*                                                     getSectionRecord() const                { return fAliasOf.getSectionRecord(); }
-       virtual unsigned int                                            getSectionIndex() const                 { return fAliasOf.getSectionIndex(); }
-       virtual bool                                                            isAlias() const                                 { return true; }
-
-protected:
-       typedef typename A::P                                           P;
-       typedef typename std::vector<Reference<A>*>                     ReferenceVector;
-       typedef typename ReferenceVector::iterator                      ReferenceVectorIterator;                // seems to help C++ parser
-       typedef typename ReferenceVector::const_iterator        ReferenceVectorConstIterator;   // seems to help C++ parser
-       friend class Reader<A>;
-
-                                                                                       SymbolAliasAtom(const char* name, const macho_nlist<P>*, const BaseAtom& );
-       virtual                                                                 ~SymbolAliasAtom() {}
-
-       const char*                                                                     fName;
-       const BaseAtom&                                                         fAliasOf;
-       ObjectFile::Atom::Scope                                         fScope;
-       bool                                                                            fDontDeadStrip;
-       ReferenceVector                                                         fReferences;
-};
-
-
-template <typename A>
-SymbolAliasAtom<A>::SymbolAliasAtom(const char* name, const macho_nlist<P>* symbol, const BaseAtom& aliasOf)
- : fName(name), fAliasOf(aliasOf)
-{
-       //fprintf(stderr, "SymbolAliasAtom(%p) %s\n", this, name);
-       if ( symbol != NULL ) {
-               uint8_t type =  symbol->n_type();
-               if ( (type & N_EXT) == 0 )
-                       fScope = ObjectFile::Atom::scopeTranslationUnit;
-               else if ( (type & N_PEXT) != 0 )
-                       fScope = ObjectFile::Atom::scopeLinkageUnit;
-               else
-                       fScope = ObjectFile::Atom::scopeGlobal;
-               fDontDeadStrip = ((symbol->n_desc() & (N_NO_DEAD_STRIP|REFERENCED_DYNAMICALLY)) != 0);
-       }
-       else {
-               // aliases defined on the command line are initially global scope
-               fScope = ObjectFile::Atom::scopeGlobal;
-               fDontDeadStrip = false;
-       }
-       // add follow-on reference to real atom 
-       new Reference<A>(A::kFollowOn, AtomAndOffset(this), AtomAndOffset((ObjectFile::Atom*)&aliasOf));
-}
-
-
-//
-// A TentativeAtom represents a C "common" or "tentative" defintion of data.
-// For instance, "int foo;" is neither a declaration or a definition and
-// is represented by a TentativeAtom.
-//
-template <typename A>
-class TentativeAtom : public BaseAtom
-{
-public:
-       virtual ObjectFile::Reader*                                     getFile() const                                 { return &fOwner; }
-       virtual bool                                                            getTranslationUnitSource(const char** dir, const char** name) const
-                                                                                                                                                               { return fOwner.getTranslationUnitSource(dir, name); }
-       virtual const char*                                                     getName() const                                 { return &fOwner.fStrings[fSymbol->n_strx()]; }
-       virtual const char*                                                     getDisplayName() const                  { return getName(); }
-       virtual ObjectFile::Atom::Scope                         getScope() const                                { return fScope; }
-       virtual ObjectFile::Atom::DefinitionKind        getDefinitionKind() const               { return ObjectFile::Atom::kTentativeDefinition; }
-       virtual bool                                                            isZeroFill() const                              { return fOwner.fOptions.fOptimizeZeroFill; }
-       virtual bool                                                            isThumb() const                                 { return false; }
-       virtual SymbolTableInclusion                            getSymbolTableInclusion() const { return ((fSymbol->n_desc() & REFERENCED_DYNAMICALLY) != 0)
-                                                                                                                                                                               ? ObjectFile::Atom::kSymbolTableInAndNeverStrip : ObjectFile::Atom::kSymbolTableIn; }
-       virtual bool                                                            dontDeadStrip() const                   { return ((fSymbol->n_desc() & (N_NO_DEAD_STRIP|REFERENCED_DYNAMICALLY)) != 0); }
-       virtual uint64_t                                                        getSize() const                                 { return fSymbol->n_value(); }
-       virtual std::vector<ObjectFile::Reference*>&  getReferences() const                     { return fgNoReferences; }
-       virtual bool                                                            mustRemainInSection() const             { return true; }
-       virtual const char*                                                     getSectionName() const;
-       virtual ObjectFile::Segment&                            getSegment() const                              { return DataSegment::fgSingleton; }
-       virtual ObjectFile::Atom&                                       getFollowOnAtom() const                 { return *(ObjectFile::Atom*)NULL; }
-       virtual std::vector<ObjectFile::LineInfo>*      getLineInfo() const                             { return NULL; }
-       virtual ObjectFile::Alignment                           getAlignment() const;
-       virtual void                                                            copyRawContent(uint8_t buffer[]) const;
-       virtual void                                                            setScope(ObjectFile::Atom::Scope newScope)              { fScope = newScope; }
-       virtual void                                                            setSize(uint64_t size)                  { }
-       virtual void                                                            addReference(ObjectFile::Reference* ref) { throw "ld: can't add references"; }
-       virtual void                                                            sortReferences() { }
-       virtual void                                                            addLineInfo(const  ObjectFile::LineInfo& info)  { throw "ld: can't add line info to tentative definition"; }
-       virtual const ObjectFile::ReaderOptions&        getOptions() const                              { return fOwner.fOptions; }
-       virtual uint64_t                                                        getObjectAddress() const                { return ULLONG_MAX; }
-       virtual const void*                                                     getSectionRecord() const                { return NULL; }
-       virtual unsigned int                                            getSectionIndex() const                 { return 0; }
-
-protected:
-       typedef typename A::P                                   P;
-       typedef typename A::P::E                                E;
-       typedef typename A::P::uint_t                   pint_t;
-       typedef typename A::ReferenceKinds              Kinds;
-       friend class Reader<A>;
-
-                                                                                       TentativeAtom(Reader<A>&, const macho_nlist<P>*);
-       virtual                                                                 ~TentativeAtom() {}
-
-       Reader<A>&                                                                      fOwner;
-       const macho_nlist<P>*                                           fSymbol;
-       ObjectFile::Atom::Scope                                         fScope;
-       static std::vector<ObjectFile::Reference*>      fgNoReferences;
-};
-
-template <typename A>
-std::vector<ObjectFile::Reference*> TentativeAtom<A>::fgNoReferences;
-
-template <typename A>
-TentativeAtom<A>::TentativeAtom(Reader<A>& owner, const macho_nlist<P>* symbol)
- : fOwner(owner), fSymbol(symbol)
-{
-       uint8_t type =  symbol->n_type();
-       if ( (type & N_EXT) == 0 )
-               fScope = ObjectFile::Atom::scopeTranslationUnit;
-       else if ( (type & N_PEXT) != 0 )
-               fScope = ObjectFile::Atom::scopeLinkageUnit;
-       else
-               fScope = ObjectFile::Atom::scopeGlobal;
-       if ( ((type & N_TYPE) == N_UNDF) && (symbol->n_value() != 0) ) {
-               // tentative definition
-       }
-       else {
-               warning("unknown symbol type: %d", type);
-       }
-       //fprintf(stderr, "TentativeAtom(%p) %s\n", this, this->getDisplayName());
-}
-
-
-template <typename A>
-ObjectFile::Alignment TentativeAtom<A>::getAlignment() const
-{
-       uint8_t alignment = GET_COMM_ALIGN(fSymbol->n_desc());
-       if ( alignment == 0 ) {
-               // common symbols align to their size
-               // that is, a 4-byte common aligns to 4-bytes
-               // if this size is not a power of two, 
-               // then round up to the next power of two
-               uint64_t size = this->getSize();
-               alignment = 63 - (uint8_t)__builtin_clzll(size);
-               if ( size != (1ULL << alignment) )
-                       ++alignment;
-       }
-       // limit alignment of extremely large commons to 2^15 bytes (8-page)
-       if ( alignment < 12 )
-               return ObjectFile::Alignment(alignment);
-       else
-               return ObjectFile::Alignment(12);
-}
-
-template <typename A>
-const char* TentativeAtom<A>::getSectionName() const
-{
-       if ( fOwner.fOptions.fForFinalLinkedImage || fOwner.fOptions.fMakeTentativeDefinitionsReal )
-               return "__common"; 
-       else
-               return "._tentdef"; 
-}
-
-
-template <typename A>
-void TentativeAtom<A>::copyRawContent(uint8_t buffer[]) const
-{
-       bzero(buffer, getSize());
-}
-
-
-//
-// An AnonymousAtom represents compiler generated data that has no name.
-// For instance, a literal C-string or a 64-bit floating point constant
-// is represented by an AnonymousAtom.
-//
-template <typename A>
-class AnonymousAtom : public BaseAtom
-{
-public:
-       virtual ObjectFile::Reader*                                     getFile() const                                 { return &fOwner; }
-       virtual bool                                                            getTranslationUnitSource(const char** dir, const char** name) const { return false; }
-       virtual const char*                                                     getName() const                                 { return fSynthesizedName; }
-       virtual const char*                                                     getDisplayName() const;
-       virtual ObjectFile::Atom::Scope                         getScope() const;
-       virtual ObjectFile::Atom::DefinitionKind        getDefinitionKind() const       { return fKind; }
-       virtual ObjectFile::Atom::ContentType           getContentType() const                  { return fType; }
-       virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const  { return fSymbolTableInclusion; }
-       virtual bool                                                            dontDeadStrip() const                   { return fDontDeadStrip; }
-       virtual bool                                                            isZeroFill() const;
-       virtual bool                                                            isThumb() const                                 { return false; }
-       virtual uint64_t                                                        getSize() const                                 { return fSize; }
-       virtual std::vector<ObjectFile::Reference*>&  getReferences() const                     { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
-       virtual bool                                                            mustRemainInSection() const             { return true; }
-       virtual const char*                                                     getSectionName() const;
-       virtual Segment<A>&                                                     getSegment() const                              { return *fSegment; }
-       virtual ObjectFile::Atom&                                       getFollowOnAtom() const;
-       virtual std::vector<ObjectFile::LineInfo>*      getLineInfo() const                             { return NULL; }
-       virtual ObjectFile::Alignment                           getAlignment() const;
-       virtual void                                                            copyRawContent(uint8_t buffer[]) const;
-       virtual void                                                            setScope(ObjectFile::Atom::Scope newScope)      { fScope = newScope; }
-       virtual void                                                            setSize(uint64_t size)                  { fSize = size; }
-       virtual void                                                            addReference(ObjectFile::Reference* ref) { fReferences.push_back((Reference<A>*)ref); }
-       virtual void                                                            sortReferences() { std::sort(fReferences.begin(), fReferences.end(), ReferenceSorter()); }
-       virtual void                                                            addLineInfo(const  ObjectFile::LineInfo& info);
-       virtual const ObjectFile::ReaderOptions&        getOptions() const                              { return fOwner.fOptions; }
-       virtual uint64_t                                                        getObjectAddress() const                { return fAddress; }
-       virtual const void*                                                     getSectionRecord() const                { return (const void*)fSection; }
-       virtual unsigned int                                            getSectionIndex() const                 { return fSectionIndex; }
-       BaseAtom*                                                                       redirectTo()                                    { return fRedirect; }
-       bool                                                                            isWeakImportStub()                              { return fWeakImportStub; }
-       void                                                                            resolveName();
-       virtual uint8_t                                                         getLSDAReferenceKind() const;
-       virtual uint8_t                                                         getPersonalityReferenceKind() const;
-       virtual uint32_t                                                        getCompactUnwindEncoding(uint64_t ehAtomAddress);
-       
-protected:
-       typedef typename A::P                                           P;
-       typedef typename A::P::E                                        E;
-       typedef typename A::P::uint_t                           pint_t;
-       typedef typename A::ReferenceKinds                      Kinds;
-       typedef typename std::vector<Reference<A>*>                     ReferenceVector;
-       typedef typename ReferenceVector::iterator                      ReferenceVectorIterator;                // seems to help C++ parser
-       typedef typename ReferenceVector::const_iterator        ReferenceVectorConstIterator;   // seems to help C++ parser
-       friend class Reader<A>;
-
-                                                                                       AnonymousAtom(Reader<A>&, const macho_section<P>*, pint_t addr, pint_t size);
-       virtual                                                                 ~AnonymousAtom() {}
-       static bool                                                                     cstringsHaveLabels();
-
-       Reader<A>&                                                                      fOwner;
-       const char*                                                                     fSynthesizedName;
-       const char*                                                                     fDisplayName;
-       const macho_section<P>*                                         fSection;
-       pint_t                                                                          fAddress;
-       pint_t                                                                          fSize;
-       Segment<A>*                                                                     fSegment;
-       ReferenceVector                                                         fReferences;
-       BaseAtom*                                                                       fRedirect;
-       bool                                                                            fDontDeadStrip;
-       bool                                                                            fWeakImportStub;
-       ObjectFile::Atom::SymbolTableInclusion          fSymbolTableInclusion;
-       ObjectFile::Atom::Scope                                         fScope;
-    ObjectFile::Atom::DefinitionKind            fKind;
-       ObjectFile::Atom::ContentType                           fType;
-       unsigned int                                                            fSectionIndex;
-};
-
-template <typename A>
-AnonymousAtom<A>::AnonymousAtom(Reader<A>& owner, const macho_section<P>* section, pint_t addr, pint_t size)
- : fOwner(owner), fSynthesizedName(NULL), fDisplayName(NULL), fSection(section), fAddress(addr), fSize(size), 
-       fSegment(NULL), fDontDeadStrip(true), fWeakImportStub(false), fSymbolTableInclusion(ObjectFile::Atom::kSymbolTableNotIn),
-       fScope(ObjectFile::Atom::scopeTranslationUnit), fKind(ObjectFile::Atom::kRegularDefinition), 
-       fType(ObjectFile::Atom::kUnclassifiedType), fSectionIndex(1 + (section - owner.fSectionsStart))
-{
-       fSegment = new Segment<A>(fSection);
-       fRedirect = this;
-       uint8_t type = fSection->flags() & SECTION_TYPE;
-       //fprintf(stderr, "AnonymousAtom(%p) addr=0x%llX in %s from %s\n", this, (long long)addr, section->sectname(), owner.getPath());
-       switch ( type ) {
-               case S_ZEROFILL:
-                       {
-                               asprintf((char**)&fSynthesizedName, "zero-fill-at-0x%08X", addr);
-                       }
-                       break;
-               case S_COALESCED:
-               case S_REGULAR:
-                       if ( section == owner.fehFrameSection ) {
-                               if ( fSize == 1 ) {
-                                       // is CIE
-                                       fSize = 0;
-                                       fDontDeadStrip = false;
-                                       if ( fOwner.fOptions.fForFinalLinkedImage ) 
-                                               fSynthesizedName = "CIE";
-                                       else
-                                               fSynthesizedName = "EH_frame1";
-                               }
-                               else {
-                                       // is FDE
-                                       fSynthesizedName = ".eh_PENDING";
-                                       fDontDeadStrip = false;
-                                       owner.fAtomsPendingAName.push_back(this);
-                               }
-                               fType = ObjectFile::Atom::kCFIType;
-                               // FDEs and CIEs don't need to be in symbol table of final linked images <rdar://problem/4180168>
-                               if ( !fOwner.fOptions.fNoEHLabels ) 
-                                       fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
-                       }
-                       else if ( (strcmp(section->sectname(), "__class") == 0) && (strcmp(section->segname(), "__OBJC") == 0) && owner.fAppleObjc ) {
-                               // special case ObjC classes to synthesize .objc_class_name_* symbols, for Apple runtime only
-                               fSynthesizedName = ".objc_class_name_PENDING";
-                               owner.fAtomsPendingAName.push_back(this);
-                               owner.fSectionsWithAtomsPendingAName.insert(fSection);
-                               if ( fOwner.fOptions.fForFinalLinkedImage ) 
-                                       fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
-                               else
-                                       fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableInAsAbsolute;
-                               fScope = ObjectFile::Atom::scopeGlobal;
-                       }
-                       else if ( strcmp(fSection->sectname(), "__cstring") == 0 ) {
-                               // handle .o files created by old ld64 -r that are missing cstring section type
-                               const char* str = (char*)(owner.fHeader) + section->offset() + addr - section->addr();
-                               asprintf((char**)&fSynthesizedName, "cstring=%s", str);
-                       }
-                       else if ((strcmp(section->sectname(), "__cfstring") == 0) && (strcmp(section->segname(), "__DATA") == 0)) {
-                               fSynthesizedName = "cfstring-pointer-name-PENDING";
-                               fScope = ObjectFile::Atom::scopeLinkageUnit;
-                               owner.fAtomsPendingAName.push_back(this);
-                               owner.fSectionsWithAtomsPendingAName.insert(fSection);
-                               fDontDeadStrip = false;
-                               fKind = ObjectFile::Atom::kWeakDefinition;
-                       }
-                       else if ( (fSection->flags() & S_ATTR_SOME_INSTRUCTIONS) != 0 ) {
-                               fDontDeadStrip = false;
-                               asprintf((char**)&fSynthesizedName, "anon-func-0x%X", addr);
-                       }
-                       else if ( strncmp(fSection->sectname(), "__gcc_except_tab",16) == 0 ) {
-                               fType = ObjectFile::Atom::kLSDAType;
-                               fDontDeadStrip = false;
-                               fSynthesizedName = ".lsda_PENDING";
-                               owner.fAtomsPendingAName.push_back(this);
-                               if ( !fOwner.fOptions.fNoEHLabels ) 
-                                       fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
-                       }
-                       else if ( (strncmp(fSection->sectname(), "__objc_classrefs", 16) == 0) && (strcmp(fSection->segname(), "__DATA") == 0) ) {
-                               fSynthesizedName = "objc-class-pointer-name-PENDING";
-                               fScope = ObjectFile::Atom::scopeLinkageUnit;
-                               owner.fAtomsPendingAName.push_back(this);
-                               owner.fSectionsWithAtomsPendingAName.insert(fSection);
-                               fKind = ObjectFile::Atom::kWeakDefinition;
-                       }
-                       else if ( section == owner.fUTF16Section ) {
-                               if ( fOwner.fOptions.fForFinalLinkedImage ) {
-                                       fDontDeadStrip = false;
-                                       fScope = ObjectFile::Atom::scopeLinkageUnit;
-                                       fKind = ObjectFile::Atom::kWeakDefinition;
-                                       char* name = new char[16+5*size];
-                                       strcpy(name, "utf16-string=");
-                                       char* s = &name[13];
-                                       const uint16_t* words = (uint16_t*)((char*)(owner.fHeader) + section->offset() + addr - section->addr());
-                                       unsigned int wordCount = size/2;
-                                       bool needSeperator = false;
-                                       for(unsigned int i=0; i < wordCount; ++i) {
-                                               if ( needSeperator )
-                                                       strcpy(s++, ".");
-                                               sprintf(s, "%04X", E::get32(words[i]));
-                                               s += 4;
-                                               needSeperator = true;
-                                       }
-                                       fSynthesizedName = name;
-                               }
-                               else {
-                                       asprintf((char**)&fSynthesizedName, "lutf16-0x%X", addr);
-                               }
-                       }
-                       break;
-               case S_CSTRING_LITERALS:
-                       {
-                               const char* str = (char*)(owner.fHeader) + section->offset() + addr - section->addr();
-                               if ( (strcmp(fSection->sectname(), "__cstring") == 0) && (strcmp(section->segname(), "__TEXT") == 0) ) 
-                                       asprintf((char**)&fSynthesizedName, "cstring=%s", str);
-                               else
-                                       asprintf((char**)&fSynthesizedName, "cstring%s%s=%s", fSection->segname(), fSection->sectname(), str);
-                               fScope = ObjectFile::Atom::scopeLinkageUnit;
-                               fKind = ObjectFile::Atom::kWeakDefinition;
-                               fType = ObjectFile::Atom::kCStringType;
-                               fDontDeadStrip = false;
-                               if ( !fOwner.fOptions.fForFinalLinkedImage && cstringsHaveLabels() ) 
-                                       fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
-                       }
-                       break;
-               case S_4BYTE_LITERALS:
-                       {
-                               uint32_t value =  E::get32(*(uint32_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
-                               asprintf((char**)&fSynthesizedName, "4-byte-literal=0x%08X", value);
-                               fScope = ObjectFile::Atom::scopeLinkageUnit;
-                               fKind = ObjectFile::Atom::kWeakDefinition;
-                               fDontDeadStrip = false;
-                       }
-                       break;
-               case S_8BYTE_LITERALS:
-                       {
-                               uint64_t value =  E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
-                               asprintf((char**)&fSynthesizedName, "8-byte-literal=0x%016llX", value);
-                               fScope = ObjectFile::Atom::scopeLinkageUnit;
-                               fKind = ObjectFile::Atom::kWeakDefinition;
-                               fDontDeadStrip = false;
-                       }
-                       break;
-               case S_16BYTE_LITERALS:
-                       {
-                               uint64_t value1 =  E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
-                               uint64_t value2 =  E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr + 8 - section->addr()));
-                               asprintf((char**)&fSynthesizedName, "16-byte-literal=0x%016llX,%016llX", value1, value2);
-                               fScope = ObjectFile::Atom::scopeLinkageUnit;
-                               fKind = ObjectFile::Atom::kWeakDefinition;
-                               fDontDeadStrip = false;
-                       }
-                       break;
-               case S_LITERAL_POINTERS:
-                       {
-                               //uint32_t literalNameAddr =  P::getP(*(pint_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
-                               //const char* str = (char*)(owner.fHeader) + section->offset() + literalNameAddr - section->addr();
-                               //asprintf((char**)&fSynthesizedName, "literal-pointer@%s@%s@%s", section->segname(), section->sectname(), str);
-                               fSynthesizedName = "literal-pointer-name-PENDING";
-                               fScope = ObjectFile::Atom::scopeLinkageUnit;
-                               fKind = ObjectFile::Atom::kWeakDefinition;
-                               fDontDeadStrip = false;
-                               owner.fAtomsPendingAName.push_back(this);
-                               owner.fSectionsWithAtomsPendingAName.insert(fSection);
-                       }
-                       break;
-               case S_MOD_INIT_FUNC_POINTERS:
-                               asprintf((char**)&fSynthesizedName, "initializer$%d", (addr - (uint32_t)fSection->addr())/sizeof(pint_t));
-                               break;
-               case S_MOD_TERM_FUNC_POINTERS:
-                               asprintf((char**)&fSynthesizedName, "terminator$%d", (addr - (uint32_t)fSection->addr())/sizeof(pint_t));
-                               break;
-               case S_SYMBOL_STUBS:
-                       {
-                               uint32_t index = (fAddress - fSection->addr()) / fSection->reserved2();
-                               index += fSection->reserved1();
-                               uint32_t symbolIndex = E::get32(fOwner.fIndirectTable[index]);
-                               const macho_nlist<P>* sym = &fOwner.fSymbols[symbolIndex];
-                               uint32_t strOffset = sym->n_strx();
-                               // want name to not have $stub suffix, this is what automatic stub generation expects
-                               fSynthesizedName = &fOwner.fStrings[strOffset];
-                               // check for weak import
-                               fWeakImportStub = fOwner.isWeakImportSymbol(sym);
-                               // sometimes the compiler gets confused and generates a stub to a static function
-                               // if so, we should redirect any call to the stub to be calls to the real static function atom
-                               if ( ((sym->n_type() & N_TYPE) != N_UNDF) && ((sym->n_type() & N_EXT) == 0) ) {
-                                       BaseAtom* staticAtom = fOwner.findAtomByName(fSynthesizedName);
-                                       if ( staticAtom != NULL ) 
-                                               fRedirect = staticAtom;
-                               }
-                               fKind = ObjectFile::Atom::kWeakDefinition;
-                               // might be a spurious stub for a static function, make stub static too
-                               if ( (sym->n_type() & N_EXT) == 0 ) 
-                                       fScope = ObjectFile::Atom::scopeTranslationUnit;
-                               else
-                                       fScope = ObjectFile::Atom::scopeLinkageUnit;
-                       }
-                       break;
-               case S_LAZY_SYMBOL_POINTERS:
-               case S_NON_LAZY_SYMBOL_POINTERS:
-                       {
-                               // transform i386 __IMPORT/__pointers to __DATA/__nl_symbol_ptr when 
-                               // generating the new compressed LINKEDIT format
-                               if ( (type == S_NON_LAZY_SYMBOL_POINTERS) && fOwner.fOptions.fMakeCompressedDyldInfo && (strcmp(fSection->segname(),"__IMPORT") == 0) ) {
-                                       macho_section<P>* dummySection = new macho_section<P>(*fSection);
-                                       dummySection->set_segname("__DATA");
-                                       dummySection->set_sectname("__nl_symbol_ptr");
-                                       fSection = dummySection;
-                                       fSegment = new Segment<A>(fSection);
-                               }
-                               
-                               fDontDeadStrip = false;
-                               fScope = ObjectFile::Atom::scopeLinkageUnit;
-                               uint32_t index = (fAddress - fSection->addr()) / sizeof(pint_t);
-                               index += fSection->reserved1();
-                               uint32_t symbolIndex = E::get32(fOwner.fIndirectTable[index]);
-                               if ( symbolIndex == INDIRECT_SYMBOL_LOCAL ) {
-                                       // Silly codegen with non-lazy pointer to a local symbol
-                                       uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
-                                       pint_t nonLazyPtrValue = P::getP(*((pint_t*)((char*)(fOwner.fHeader)+fileOffset)));
-                                       // All atoms not created yet, so we need to scan symbol table
-                                       const macho_nlist<P>* closestSym = NULL; 
-                                       const macho_nlist<P>* end = &fOwner.fSymbols[fOwner.fSymbolCount];
-                                       for (const macho_nlist<P>* sym =  fOwner.fSymbols; sym < end; ++sym) {
-                                               if ( ((sym->n_type() & N_TYPE) == N_SECT) 
-                                                && ((sym->n_type() & N_STAB) == 0) ) {
-                                                       if ( sym->n_value() == nonLazyPtrValue ) {
-                                                               const char* name = &fOwner.fStrings[sym->n_strx()];
-                                                               char* str = new char[strlen(name)+16];
-                                                               strcpy(str, name);
-                                                               strcat(str, "$non_lazy_ptr");
-                                                               fSynthesizedName = str;
-                                                               // add direct reference to target later, because its atom may not be constructed yet
-                                                               fOwner.fLocalNonLazys.push_back(this);
-                                                               fScope = ObjectFile::Atom::scopeTranslationUnit;
-                                                               fType = ObjectFile::Atom::kNonLazyPointer;
-                                                               return;
-                                                       }
-                                                       else if ( (sym->n_value() < nonLazyPtrValue) && ((closestSym == NULL) || (sym->n_value() > closestSym->n_value())) ) {
-                                                               closestSym = sym;
-                                                       }
-                                               }
-                                       }
-                                       // add direct reference to target later, because its atom may not be constructed yet
-                                       if ( closestSym != NULL ) {
-                                               const char* name = &fOwner.fStrings[closestSym->n_strx()];
-                                               char* str;
-                                               asprintf(&str, "%s+%u$non_lazy_ptr", name, nonLazyPtrValue - closestSym->n_value());
-                                               fSynthesizedName = str;
-                                       }
-                                       else {
-                                               fSynthesizedName = "$interior$non_lazy_ptr";
-                                       }
-                                       fScope = ObjectFile::Atom::scopeTranslationUnit;
-                                       fOwner.fLocalNonLazys.push_back(this);
-                                       fType = ObjectFile::Atom::kNonLazyPointer;
-                                       return;
-                               }
-                               const macho_nlist<P>* targetSymbol = &fOwner.fSymbols[symbolIndex];
-                               const char* name = &fOwner.fStrings[targetSymbol->n_strx()];
-                               char* str = new char[strlen(name)+16];
-                               strcpy(str, name);
-                               if ( type == S_LAZY_SYMBOL_POINTERS ) {
-                                       strcat(str, "$lazy_ptr");
-                                       fType = ObjectFile::Atom::kLazyPointer;
-                               }
-                               else {
-                                       strcat(str, "$non_lazy_ptr");
-                                       fType = ObjectFile::Atom::kNonLazyPointer;
-                               }
-                               fSynthesizedName = str;
-
-                               if ( type == S_NON_LAZY_SYMBOL_POINTERS )
-                                       fKind = ObjectFile::Atom::kWeakDefinition;
-                               
-                               if ( (targetSymbol->n_type() & N_EXT) == 0 ) {
-                                       // target is translation unit scoped, so add direct reference to target
-                                       //fOwner.makeReference(A::kPointer, addr, targetSymbol->n_value());
-                                       new Reference<A>(A::kPointer, AtomAndOffset(this), fOwner.findAtomAndOffset(targetSymbol->n_value()));
-                               }
-                               else {  
-                                       if ( fOwner.isWeakImportSymbol(targetSymbol) )
-                                               new Reference<A>(A::kPointerWeakImport, AtomAndOffset(this), name, 0);
-                                       else
-                                               new Reference<A>(A::kPointer, AtomAndOffset(this), name, 0);
-                               }
-                       }
-                       break;
-               default:
-                       throwf("section type %d not supported with address=0x%08llX", type, (uint64_t)addr);
-       }
-       //fprintf(stderr, "AnonymousAtom(%p) %s \n", this, this->getDisplayName());
-}
-
-// x86_64 uses L labels on cstrings to allow relocs with addends
-template <> bool AnonymousAtom<x86_64>::cstringsHaveLabels() { return true; }
-template <typename A> bool AnonymousAtom<A>::cstringsHaveLabels() { return false; }
-
-template <typename A>
-void AnonymousAtom<A>::addLineInfo(const ObjectFile::LineInfo& info) 
-{ 
-       // <rdar://problem/6545406> don't warn if line table has entries for stubs
-       if ( (fSection->flags() & SECTION_TYPE) != S_SYMBOL_STUBS )
-               warning("can't add line info to anonymous symbol %s from %s", this->getDisplayName(), this->getFile()->getPath()); 
-}
-
-template <typename A>
-void AnonymousAtom<A>::resolveName()
-{
-       if ( (strcmp(fSection->sectname(), "__class") == 0) && (strcmp(fSection->segname(), "__OBJC") == 0) ) {
-               std::vector<ObjectFile::Reference*>&  references = this->getReferences();
-               // references are not yet sorted, so scan the vector
-               for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
-                       if ( ((*rit)->getFixUpOffset() == sizeof(pint_t)) && ((*rit)->getKind() == A::kPointer) ) {
-                               const char* superStr = (*rit)->getTargetName();
-                               if ( strncmp(superStr, "cstring", 7) == 0 ) {
-                                       const char* superClassName;
-                                       asprintf((char**)&superClassName, ".objc_class_name_%s", &superStr[8]);
-                                       new Reference<A>(A::kNoFixUp, AtomAndOffset(this), superClassName, 0);
-                               }
-                               break;
-                       }
-               }
-               for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
-                       if ( ((*rit)->getFixUpOffset() == 2*sizeof(pint_t)) && ((*rit)->getKind() == A::kPointer) ) {
-                               const char* classStr = (*rit)->getTargetName();
-                               if ( strncmp(classStr, "cstring", 7) == 0 ) {
-                                       asprintf((char**)&fSynthesizedName, ".objc_class_name_%s", &classStr[8]);
-                               }
-                               break;
-                       }
-               }
-       }
-       else if ( (fSection->flags() & SECTION_TYPE) == S_LITERAL_POINTERS) {
-               std::vector<ObjectFile::Reference*>&  references = this->getReferences();
-               if ( references.size() < 1 )
-                       throwf("S_LITERAL_POINTERS section %s,%s missing relocs", fSection->segname(), fSection->sectname());
-               ObjectFile::Reference* ref = references[0];
-               const char* str = ref->getTargetName();
-               if ( strncmp(str, "cstring", 7) == 0 ) {
-                       asprintf((char**)&fSynthesizedName, "literal-pointer@%s@%s@%s", fSection->segname(), fSection->sectname(), &str[8]);
-               }
-       }
-       else if ( (strcmp(fSection->sectname(), "__cfstring") == 0) && (strcmp(fSection->segname(), "__DATA") == 0) ) {
-               // references are not yet sorted, so scan the vector
-               std::vector<ObjectFile::Reference*>&  references = this->getReferences();
-               for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
-                       if ( ((*rit)->getFixUpOffset() == 2*sizeof(pint_t)) && ((*rit)->getKind() == A::kPointer) ) {
-                               const char* superStr = (*rit)->getTargetName();
-                               if ( (superStr != NULL) && (strncmp(superStr, "cstring=", 8) == 0) ) {
-                                       asprintf((char**)&fSynthesizedName, "cfstring=%s", &superStr[8]);
-                               }
-                               else if ( (superStr != NULL) && (strncmp(superStr, "utf16-string=", 13) == 0) ) {
-                                       asprintf((char**)&fSynthesizedName, "cfstring-utf16=%s", &superStr[13]);
-                               }
-                               else {
-                                       // compiled with -fwritable-strings or a non-ASCII string 
-                                       fKind = ObjectFile::Atom::kRegularDefinition; // these are not coalescable
-                                       fScope = ObjectFile::Atom::scopeTranslationUnit;
-                                       fSynthesizedName = "cfstring-not-coalesable";
-                                       if ( (*rit)->getTargetOffset() != 0 )
-                                               warning("-fwritable-strings not compatible with literal CF/NSString in %s", fOwner.getPath());
-                               }
-                               break;
-                       }
-               }
-       }
-       else if ( fSection == fOwner.fehFrameSection ) {
-               // give name to FDE
-               ObjectFile::Atom* funcAtom = fOwner.getFunctionAtomFromFDEAddress(fAddress);
-               if ( funcAtom != NULL )
-                       asprintf((char**)&fSynthesizedName, "%s.eh", funcAtom->getDisplayName());
-       }
-       else if ( fOwner.fLSDAAtoms.count(this) != 0) {
-               // give name to LSDA
-               ObjectFile::Atom* funcAtom = fOwner.getFunctionAtomFromLSDAAddress(fAddress);
-               if ( funcAtom != NULL )
-                       asprintf((char**)&fSynthesizedName, "%s.lsda", funcAtom->getDisplayName());
-       }
-       else if ( (strncmp(fSection->sectname(),  "__objc_classrefs", 16) == 0) && (strcmp(fSection->segname(), "__DATA") == 0) ) {
-               std::vector<ObjectFile::Reference*>& references = this->getReferences();
-               if ( references.size() != 1 )
-                       throwf("__objc_classrefs element missing reloc (count=%ld) for target class in %s", references.size(), fOwner.getPath());
-               const char* targetName = references[0]->getTargetName();
-               if ( strncmp(targetName, "_OBJC_CLASS_$_", 14) == 0 )
-                       asprintf((char**)&fSynthesizedName, "objc-class-ref-to-%s", &targetName[14]);
-               else
-                       asprintf((char**)&fSynthesizedName, "objc-class-ref-to-%s", targetName);
-       }
-}
-
-
-template <typename A>
-const char* AnonymousAtom<A>::getDisplayName() const
-{
-       if ( fSynthesizedName != NULL )
-               return fSynthesizedName;
-
-       if ( fDisplayName != NULL )
-               return fDisplayName;
-
-       if ( (fSection->flags() & SECTION_TYPE) == S_CSTRING_LITERALS ) {
-               uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
-               asprintf((char**)&fDisplayName, "atom string literal: \"%s\"", (char*)(fOwner.fHeader)+fileOffset);
-       }
-       else {
-               asprintf((char**)&fDisplayName, "%s@%d", fSection->sectname(), fAddress - (uint32_t)fSection->addr() );
-       }
-       return fDisplayName;
-}
-
-
-template <typename A>
-ObjectFile::Atom::Scope AnonymousAtom<A>::getScope() const
-{
-       return fScope;
-}
-
-
-template <typename A>
-bool AnonymousAtom<A>::isZeroFill() const
-{
-       return ( ((fSection->flags() & SECTION_TYPE) == S_ZEROFILL) && fOwner.fOptions.fOptimizeZeroFill );
-}
-
-
-template <typename A>
-const char*    AnonymousAtom<A>::getSectionName() const
-{
-       if ( fOwner.fOptions.fForFinalLinkedImage ) {
-               switch ( fSection->flags() & SECTION_TYPE ) {
-                       case S_4BYTE_LITERALS:
-                       case S_8BYTE_LITERALS:
-                       case S_16BYTE_LITERALS:
-                               return "__const";
-               }
-       }
-       
-       if ( strlen(fSection->sectname()) > 15 ) {
-               static char temp[18];
-               strncpy(temp, fSection->sectname(), 16);
-               temp[17] = '\0';
-               return temp;
-       }
-       return fSection->sectname();
-}
-
-template <typename A>
-ObjectFile::Alignment AnonymousAtom<A>::getAlignment() const
-{
-       // FDEs and CIEs are always packed together in a final linked image, so ignore section alignment
-       if ( fType == ObjectFile::Atom::kCFIType )
-               return ObjectFile::Alignment(0);
-               
-       switch ( fSection->flags() & SECTION_TYPE ) {
-               case S_4BYTE_LITERALS:
-                       return ObjectFile::Alignment(2);
-               case S_8BYTE_LITERALS:
-                       return ObjectFile::Alignment(3);
-               case S_16BYTE_LITERALS:
-                       return ObjectFile::Alignment(4);
-               case S_NON_LAZY_SYMBOL_POINTERS:
-                       return ObjectFile::Alignment((uint8_t)log2(sizeof(pint_t)));
-               case S_CSTRING_LITERALS:
-                       if ( ! fOwner.fOptions.fForFinalLinkedImage )
-                               return ObjectFile::Alignment(fSection->align());
-               default:
-                       return ObjectFile::Alignment(fSection->align(), fAddress % (1 << fSection->align()));
-       }
-}
-
-
-template <typename A>
-ObjectFile::Atom& AnonymousAtom<A>::getFollowOnAtom() const
-{
-       for (ReferenceVectorConstIterator it=fReferences.begin(); it != fReferences.end(); it++) {
-               Reference<A>* ref = *it;
-               if ( ref->getKind() == A::kFollowOn )
-                       return ref->getTarget();
-       }
-       return *((ObjectFile::Atom*)NULL);
-}
-
-template <typename A>
-void AnonymousAtom<A>::copyRawContent(uint8_t buffer[]) const
-{
-       // copy base bytes
-       if ( isZeroFill() )
-               bzero(buffer, fSize);
-       else {
-               uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
-               memcpy(buffer, (char*)(fOwner.fHeader)+fileOffset, fSize);
-       }
-}
-
-//
-// An AbsoluteAtom represents an N_ABS symbol which can only be created in 
-// assembly language and usable by static executables such as the kernel/
-//
-template <typename A>
-class AbsoluteAtom : public BaseAtom
-{
-public:
-       virtual ObjectFile::Reader*                                     getFile() const                                 { return &fOwner; }
-       virtual bool                                                            getTranslationUnitSource(const char** dir, const char** name) const
-                                                                                                                                                               { return fOwner.getTranslationUnitSource(dir, name); }
-       virtual const char*                                                     getName() const                                 { return &fOwner.fStrings[fSymbol->n_strx()]; }
-       virtual const char*                                                     getDisplayName() const                  { return getName(); }
-       virtual ObjectFile::Atom::Scope                         getScope() const                                { return fScope; }
-       virtual ObjectFile::Atom::DefinitionKind        getDefinitionKind() const               { return ObjectFile::Atom::kAbsoluteSymbol; }
-       virtual bool                                                            isZeroFill() const                              { return false; }
-       virtual bool                                                            isThumb() const                                 { return ((fSymbol->n_desc() & N_ARM_THUMB_DEF) != 0); }
-       virtual SymbolTableInclusion                            getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableInAsAbsolute; }
-       virtual bool                                                            dontDeadStrip() const                   { return false; }
-       virtual uint64_t                                                        getSize() const                                 { return 0; }
-       virtual std::vector<ObjectFile::Reference*>&  getReferences() const                     { return fgNoReferences; }
-       virtual bool                                                            mustRemainInSection() const             { return true; }
-       virtual const char*                                                     getSectionName() const                  { return "._absolute"; } 
-       virtual ObjectFile::Segment&                            getSegment() const                              { return LinkEditSegment::fgSingleton; }
-       virtual ObjectFile::Atom&                                       getFollowOnAtom() const                 { return *(ObjectFile::Atom*)NULL; }
-       virtual std::vector<ObjectFile::LineInfo>*      getLineInfo() const                             { return NULL; }
-       virtual ObjectFile::Alignment                           getAlignment() const                    { return ObjectFile::Alignment(0); }
-       virtual void                                                            copyRawContent(uint8_t buffer[]) const  { }
-       virtual void                                                            setScope(ObjectFile::Atom::Scope newScope)              { fScope = newScope; }
-       virtual void                                                            setSize(uint64_t size)                  { }
-       virtual void                                                            addReference(ObjectFile::Reference* ref) { throw "ld: can't add references"; }
-       virtual void                                                            sortReferences()                                { }
-       virtual void                                                            addLineInfo(const  ObjectFile::LineInfo& info)  { throw "ld: can't add line info to tentative definition"; }
-       virtual const ObjectFile::ReaderOptions&        getOptions() const                              { return fOwner.fOptions; }
-       virtual uint64_t                                                        getObjectAddress() const                { return fSymbol->n_value(); }
-       virtual void                                                            setSectionOffset(uint64_t offset) { /* don't let fSectionOffset be altered*/ }
-       virtual const void*                                                     getSectionRecord() const                { return NULL; }
-       virtual unsigned int                                            getSectionIndex() const                 { return 0; }
-
-protected:
-       typedef typename A::P                                   P;
-       typedef typename A::P::E                                E;
-       typedef typename A::P::uint_t                   pint_t;
-       typedef typename A::ReferenceKinds              Kinds;
-       friend class Reader<A>;
-
-                                                                                       AbsoluteAtom(Reader<A>&, const macho_nlist<P>*);
-       virtual                                                                 ~AbsoluteAtom() {}
-
-       Reader<A>&                                                                      fOwner;
-       const macho_nlist<P>*                                           fSymbol;
-       ObjectFile::Atom::Scope                                         fScope;
-       static std::vector<ObjectFile::Reference*>      fgNoReferences;
-};
-
-template <typename A>
-std::vector<ObjectFile::Reference*> AbsoluteAtom<A>::fgNoReferences;
-
-template <typename A>
-AbsoluteAtom<A>::AbsoluteAtom(Reader<A>& owner, const macho_nlist<P>* symbol)
- : fOwner(owner), fSymbol(symbol)
-{
-       // store absolute adress in fSectionOffset
-       fSectionOffset = symbol->n_value();
-       // compute scope
-       uint8_t type =  symbol->n_type();
-       if ( (type & N_EXT) == 0 )
-               fScope = ObjectFile::Atom::scopeTranslationUnit;
-       else if ( (type & N_PEXT) != 0 )
-               fScope = ObjectFile::Atom::scopeLinkageUnit;
-       else
-               fScope = ObjectFile::Atom::scopeGlobal;
-       //fprintf(stderr, "AbsoluteAtom(%p) %s\n", this, this->getDisplayName());
-}
-
-
-//
-// An SectionBoundaryAtom represent the start or end of a section
-//
-template <typename A>
-class SectionBoundaryAtom : public BaseAtom
-{
-public:
-       virtual ObjectFile::Reader*                                     getFile() const                                 { return &fOwner; }
-       virtual bool                                                            getTranslationUnitSource(const char** dir, const char** name) const
-                                                                                                                                                               { return fOwner.getTranslationUnitSource(dir, name); }
-       virtual const char*                                                     getName() const                                 { return fSymbolName; }
-       virtual const char*                                                     getDisplayName() const                  { return fDisplayName; }
-       virtual ObjectFile::Atom::Scope                         getScope() const                                { return ObjectFile::Atom::scopeLinkageUnit; }
-       virtual ObjectFile::Atom::DefinitionKind        getDefinitionKind() const               { return ObjectFile::Atom::kWeakDefinition; }
-       virtual ObjectFile::Atom::ContentType           getContentType() const                  { return fStart ? ObjectFile::Atom::kSectionStart : ObjectFile::Atom::kSectionEnd; }
-       virtual bool                                                            isZeroFill() const                              { return fZeroFill; }
-       virtual bool                                                            isThumb() const                                 { return false; }
-       virtual SymbolTableInclusion                            getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
-       virtual bool                                                            dontDeadStrip() const                   { return false; }
-       virtual uint64_t                                                        getSize() const                                 { return 0; }
-       virtual std::vector<ObjectFile::Reference*>&  getReferences() const                     { return fgNoReferences; }
-       virtual bool                                                            mustRemainInSection() const             { return true; }
-       virtual const char*                                                     getSectionName() const                  { return fSectionName; } 
-       virtual ObjectFile::Segment&                            getSegment() const                              { return *fSegment; }
-       virtual ObjectFile::Atom&                                       getFollowOnAtom() const                 { return *(ObjectFile::Atom*)NULL; }
-       virtual std::vector<ObjectFile::LineInfo>*      getLineInfo() const                             { return NULL; }
-       virtual ObjectFile::Alignment                           getAlignment() const                    { return ObjectFile::Alignment(0); }
-       virtual void                                                            copyRawContent(uint8_t buffer[]) const  { }
-       virtual void                                                            setScope(ObjectFile::Atom::Scope newScope)              { }
-       virtual void                                                            setSize(uint64_t size)                  { }
-       virtual void                                                            addReference(ObjectFile::Reference* ref) { throw "ld: can't add references"; }
-       virtual void                                                            sortReferences()                                { }
-       virtual void                                                            addLineInfo(const  ObjectFile::LineInfo& info)  { throw "ld: can't add line info to tentative definition"; }
-       virtual const ObjectFile::ReaderOptions&        getOptions() const                              { return fOwner.fOptions; }
-       virtual uint64_t                                                        getObjectAddress() const                { return 0; }
-       virtual const void*                                                     getSectionRecord() const                { return NULL; }
-       virtual unsigned int                                            getSectionIndex() const                 { return 0; }
-
-protected:
-       typedef typename A::P                                   P;
-       typedef typename A::P::E                                E;
-       typedef typename A::P::uint_t                   pint_t;
-       typedef typename A::ReferenceKinds              Kinds;
-       friend class Reader<A>;
-
-
-       class Segment : public ObjectFile::Segment
-       {
-       public:
-                                                                       Segment(const char* name, bool r, bool w, bool x): 
-                                                                               fName(name), fReadable(r), fWritable(w), fExecutable(x) {}
-                                                                               
-               virtual const char*                     getName() const                                         { return fName; }
-               virtual bool                            isContentReadable() const                       { return fReadable; }
-               virtual bool                            isContentWritable() const                       { return fWritable; }
-               virtual bool                            isContentExecutable() const                     { return fExecutable; }
-       private:
-               const char*                                     fName;
-               bool                                            fReadable;
-               bool                                            fWritable;
-               bool                                            fExecutable;
-       };
-
-                                                                                       SectionBoundaryAtom(Reader<A>&, bool start, const char* symbolName, const char* segSectName);
-       virtual                                                                 ~SectionBoundaryAtom() {}
-
-       Reader<A>&                                                                      fOwner;
-       class Segment*                                                          fSegment;
-       const char*                                                                     fSymbolName;
-       const char*                                                                     fSectionName;
-       const char*                                                                     fDisplayName;
-       bool                                                                            fStart;
-       bool                                                                            fZeroFill;
-       static std::vector<ObjectFile::Reference*>      fgNoReferences;
-};
-
-template <typename A>
-std::vector<ObjectFile::Reference*> SectionBoundaryAtom<A>::fgNoReferences;
-
-// examples:
-//                     section$start$__DATA$__my
-//                     section$end$__DATA$__my
-template <typename A>
-SectionBoundaryAtom<A>::SectionBoundaryAtom(Reader<A>& owner, bool start, const char* symbolName, const char* segSectName)
- : fOwner(owner), fSymbolName(symbolName), fSectionName(NULL), fStart(start), fZeroFill(false)
-{
-       const char* segSectDividor = strrchr(segSectName, '$');
-       if ( segSectDividor == NULL )
-               throwf("malformed section reference name: %s", symbolName);
-       fSectionName = segSectDividor + 1;
-       int segNameLen = segSectDividor - segSectName;
-       if ( segNameLen > 16 )
-               throwf("malformed section reference name: %s", symbolName);
-       char segName[18];
-       strlcpy(segName, segSectName, segNameLen+1);
-       if ( strcmp(segName, "__TEXT") == 0 )
-               fSegment = new Segment("__TEXT", true, false, true);
-       else if ( strcmp(segName, "__DATA") == 0 ) {
-               fSegment = new Segment("__DATA", true, true, false);
-               if ( (strcmp(fSectionName, "__bss") == 0) || (strcmp(fSectionName, "__common") == 0) )
-                       fZeroFill = true;
-       }       
-       else 
-               fSegment = new Segment(strdup(segName), true, true, false);
-
-       asprintf((char**)&fDisplayName, "%s of section '%s' in segment '%s'", (start ? "start" : "end"), fSectionName, segName);
-}
-
-
-
-///
-/// ObjectFileAddressSpace is used as a template parameter to UnwindCursor for parsing
-/// dwarf CFI information in an object file.   
-///
-template <typename A>
-class ObjectFileAddressSpace
-{
-public:
-                                               ObjectFileAddressSpace(Reader<A>& reader);
-
-               typedef typename A::P::uint_t   pint_t;
-               typedef typename A::P                   P;
-               typedef typename A::P::uint_t   sint_t;
-
-               uint8_t                 get8(pint_t addr);
-               uint16_t                get16(pint_t addr);
-               uint32_t                get32(pint_t addr);
-               uint64_t                get64(pint_t addr);
-               pint_t                  getP(pint_t addr);
-               uint64_t                getULEB128(pint_t& addr, pint_t end);
-               int64_t                 getSLEB128(pint_t& addr, pint_t end);
-               pint_t                  getEncodedP(pint_t& addr, pint_t end, uint8_t encoding);
-private:
-       const void*                     mappedAddress(pint_t addr, pint_t* relocTarget=NULL);
-       pint_t                          relocated(uint32_t sectOffset, uint32_t relocsOffset, uint32_t relocsCount);
-       void                            buildRelocatedMap(const macho_section<P>* sect, std::map<uint32_t,uint64_t>& map);
-       
-       Reader<A>&                              fReader;
-       const uint8_t*                  fMappingStart;
-       const macho_section<P>* fSectionsStart;
-       const macho_section<P>* fSectionsEnd;
-       std::map<uint32_t,uint64_t> fEHFrameOffsetToTargetMap;
-};
-
-
-template <typename A>
-ObjectFileAddressSpace<A>::ObjectFileAddressSpace(Reader<A>& reader)
-       : fReader(reader), fMappingStart(NULL), fSectionsStart(NULL), fSectionsEnd(NULL)
-{
-}
-
-
-
-template <typename A>
-const void* ObjectFileAddressSpace<A>::mappedAddress(pint_t addr, pint_t* relocTarget)
-{
-       if ( fMappingStart == NULL ) {
-               // delay initialization until now when fReader.fSegment is set up
-               fMappingStart = (uint8_t*)fReader.fHeader;
-               fSectionsStart = (macho_section<P>*)((char*)fReader.fSegment + sizeof(macho_segment_command<P>));
-               fSectionsEnd = &fSectionsStart[fReader.fSegment->nsects()];
-               // find __eh_frame section and build map of relocations for performance
-               buildRelocatedMap(fReader.fehFrameSection, fEHFrameOffsetToTargetMap);
-       }
-       // special case lookups in __eh_frame section to be fast
-       const macho_section<P>* ehSect = fReader.fehFrameSection;
-       if ( (ehSect->addr() <= addr) && (addr < (ehSect->addr()+ehSect->size())) ) {
-               pint_t offsetOfAddrInSection = addr - ehSect->addr();
-               if ( relocTarget != NULL ) {
-                       std::map<uint32_t,uint64_t>::iterator pos = fEHFrameOffsetToTargetMap.find(offsetOfAddrInSection);
-                       if ( pos != fEHFrameOffsetToTargetMap.end() )
-                               *relocTarget = pos->second;
-                       else
-                               *relocTarget = 0;
-               }
-               return fMappingStart + ehSect->offset() + offsetOfAddrInSection;
-       }
-       else {
-               for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
-                       if ( (sect->addr() <= addr) && (addr < (sect->addr()+sect->size())) ) {
-                               pint_t offsetOfAddrInSection = addr - sect->addr();
-                               if ( (sect->flags() & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS ) {
-                                       const uint32_t indirectTableOffset = sect->reserved1();
-                                       const uint32_t sectionIndex = offsetOfAddrInSection/sizeof(pint_t);
-                                       const uint32_t symbolIndex = A::P::E::get32(fReader.fIndirectTable[indirectTableOffset+sectionIndex]);
-                                       // return pointer to symbol name which this non-lazy-pointer will point to
-                                       if ( relocTarget != NULL )
-                                               *relocTarget = (uintptr_t)&fReader.fStrings[fReader.fSymbols[symbolIndex].n_strx()];
-                               }
-                               else {
-                                       if ( relocTarget != NULL )
-                                               *relocTarget = relocated(offsetOfAddrInSection, sect->reloff(), sect->nreloc());
-                               }
-                               return fMappingStart + sect->offset() + offsetOfAddrInSection;
-                       }
-               }
-               throwf("ObjectFileAddressSpace::mappedAddress(0x%0lX) not in any section", (long)addr);
-       }
-}
-
-
-
-
-template <typename A>
-uint8_t ObjectFileAddressSpace<A>::get8(pint_t logicalAddr)
-{
-       return *((uint8_t*)mappedAddress(logicalAddr));
-}
-
-template <typename A>
-uint16_t ObjectFileAddressSpace<A>::get16(pint_t logicalAddr)
-{
-       return P::E::get16(*((uint16_t*)mappedAddress(logicalAddr)));
-}
-
-template <typename A>
-uint32_t ObjectFileAddressSpace<A>::get32(pint_t logicalAddr)
-{
-       pint_t relocTarget;
-       return P::E::get32(*((uint32_t*)mappedAddress(logicalAddr, &relocTarget))) + relocTarget;
-}
-
-template <typename A>
-uint64_t ObjectFileAddressSpace<A>::get64(pint_t logicalAddr)
-{
-       pint_t relocTarget;
-       return P::E::get64(*((uint64_t*)mappedAddress(logicalAddr, &relocTarget))) + relocTarget;
-}
-
-template <typename A>
-typename A::P::uint_t ObjectFileAddressSpace<A>::getP(pint_t logicalAddr)
-{
-       pint_t relocTarget;
-       return P::getP(*((pint_t*)mappedAddress(logicalAddr, &relocTarget))) + relocTarget;
-}
-
-template <typename A>
-uint64_t ObjectFileAddressSpace<A>::getULEB128(pint_t& logicalAddr, pint_t end)
-{
-       uintptr_t size = (end - logicalAddr);
-       libunwind::LocalAddressSpace::pint_t laddr = (libunwind::LocalAddressSpace::pint_t)mappedAddress(logicalAddr);
-       libunwind::LocalAddressSpace::pint_t sladdr = laddr;
-       uint64_t result = libunwind::LocalAddressSpace::getULEB128(laddr, laddr+size);
-       logicalAddr += (laddr-sladdr);
-       return result;
-}
-
-template <typename A>
-int64_t ObjectFileAddressSpace<A>::getSLEB128(pint_t& logicalAddr, pint_t end)
-{
-       uintptr_t size = (end - logicalAddr);
-       libunwind::LocalAddressSpace::pint_t laddr = (libunwind::LocalAddressSpace::pint_t)mappedAddress(logicalAddr);
-       libunwind::LocalAddressSpace::pint_t sladdr = laddr;
-       int64_t result = libunwind::LocalAddressSpace::getSLEB128(laddr, laddr+size);
-       logicalAddr += (laddr-sladdr);
-       return result;
-}
-
-
-
-
-
-
-template <typename A>
-class Reader : public ObjectFile::Reader
-{
-public:
-       static bool                                                                             validFile(const uint8_t* fileContent, bool subtypeMustMatch=false, cpu_subtype_t subtype=0);
-       static const char*                                                              fileKind(const uint8_t* fileContent);
-                                                                                                       Reader(const uint8_t* fileContent, const char* path, time_t modTime, 
-                                                                                                               const ObjectFile::ReaderOptions& options, uint32_t ordinalBase);
-       virtual                                                                                 ~Reader() {}
-
-       virtual const char*                                                             getPath()                               { return fPath; }
-       virtual time_t                                                                  getModificationTime()   { return fModTime; }
-       virtual ObjectFile::Reader::DebugInfoKind               getDebugInfoKind()              { return fDebugInfo; }
-       virtual std::vector<class ObjectFile::Atom*>&   getAtoms()                              { return (std::vector<class ObjectFile::Atom*>&)(fAtoms); }
-       virtual std::vector<class ObjectFile::Atom*>*   getJustInTimeAtomsFor(const char* name) { return NULL; }
-       virtual std::vector<Stab>*                                              getStabs()                              { return &fStabs; }
-       virtual ObjectFile::Reader::ObjcConstraint              getObjCConstraint()             { return fObjConstraint; }
-    virtual uint32_t                                updateCpuConstraint(uint32_t current);
-       virtual bool                                                                    canScatterAtoms()               { return (fHeader->flags() & MH_SUBSECTIONS_VIA_SYMBOLS); }
-       virtual bool                                                                    objcReplacementClasses(){ return fReplacementClasses; }
-       virtual bool                                                                    hasLongBranchStubs()    { return fHasLongBranchStubs; }
-
-        bool                                                                                   getTranslationUnitSource(const char** dir, const char** name) const;
-
-private:
-       typedef typename A::P                                           P;
-       typedef typename A::P::E                                        E;
-       typedef typename A::P::uint_t                           pint_t;
-       //typedef typename std::vector<Atom<A>*>                AtomVector;
-       //typedef typename AtomVector::iterator         AtomVectorIterator;     // seems to help C++ parser
-       typedef typename A::ReferenceKinds                      Kinds;
-       typedef typename libunwind::CFI_Parser<ObjectFileAddressSpace<A> >::FDE_Atom_Info  FDE_Atom_Info;
-       typedef typename libunwind::CFI_Parser<ObjectFileAddressSpace<A> >::CIE_Atom_Info  CIE_Atom_Info;
-       typedef class ObjectFileAddressSpace<A> OAS;
-       friend class ObjectFileAddressSpace<A>;
-       friend class AnonymousAtom<A>;
-       friend class TentativeAtom<A>;
-       friend class AbsoluteAtom<A>;
-       friend class SectionBoundaryAtom<A>;
-       friend class SymbolAtom<A>;
-       typedef std::map<pint_t, BaseAtom*>                     AddrToAtomMap;
-
-       void                                                                            addReferencesForSection(const macho_section<P>* sect);
-       bool                                                                            addRelocReference(const macho_section<P>* sect, const macho_relocation_info<P>* reloc);
-       bool                                                                            addRelocReference_powerpc(const macho_section<P>* sect, const macho_relocation_info<P>* reloc);
-       const char*                                                                     getDwarfString(uint64_t form, const uint8_t* p);
-       bool                                                                            read_comp_unit(const char ** name, const char ** comp_dir, uint64_t *stmt_list);
-       static bool                                                                     isWeakImportSymbol(const macho_nlist<P>* sym);
-       static bool                                                                     skip_form(const uint8_t ** offset, const uint8_t * end, uint64_t form, uint8_t addr_size, bool dwarf64);
-       static const char*                                                      assureFullPath(const char* path);
-       AtomAndOffset                                                           findAtomAndOffset(pint_t addr);
-       AtomAndOffset                                                           findAtomAndOffsetForSection(pint_t addr, unsigned int sectionIndex);
-       AtomAndOffset                                                           findAtomAndOffset(pint_t baseAddr, pint_t realAddr);
-       Reference<A>*                                                           makeReference(Kinds kind, pint_t atAddr, pint_t toAddr);
-       Reference<A>*                                                           makeReference(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr);
-       Reference<A>*                                                           makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t toAddr, pint_t toBaseAddr);
-       Reference<A>*                                                           makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr, pint_t toBaseAddr);
-       Reference<A>*                                                           makeByNameReference(Kinds kind, pint_t atAddr, const char* toName, uint32_t toOffset);
-       BaseAtom*                                                                       makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section<P>* ehSect);
-       Reference<A>*                                                           makeReferenceToSymbol(Kinds kind, pint_t atAddr, const macho_nlist<P>* toSymbol, pint_t toOffset);
-       void                                                                            validSectionType(uint8_t type);
-       void                                                                            addDtraceExtraInfos(uint32_t probeAddr, const char* providerName);
-       void                                                                            setCpuConstraint(uint32_t cpusubtype);
-       const macho_section<P>*                                         getSectionForAddress(pint_t);
-       ObjectFile::Atom*                                                       getFunctionAtomFromFDEAddress(pint_t);
-       ObjectFile::Atom*                                                       getFunctionAtomFromLSDAAddress(pint_t);
-       void                                                                            addFdeReference(uint8_t encoding, AtomAndOffset inFDE, AtomAndOffset target);
-       void                                                                            addCiePersonalityReference(BaseAtom* cieAtom, uint32_t offsetInCIE, uint8_t encoding);
-       bool                                                                            isSectDiffReloc(uint8_t r_type);
-
-
-       BaseAtom*                                                                       findAtomByName(const char*);
-
-       const char*                                                                     fPath;
-       time_t                                                                          fModTime;
-       uint32_t                                                                        fOrdinalBase;
-       const ObjectFile::ReaderOptions&                        fOptions;
-       const macho_header<P>*                                          fHeader;
-       const char*                                                                     fStrings;
-       const macho_nlist<P>*                                           fSymbols;
-       uint32_t                                                                        fSymbolCount;
-       const macho_segment_command<P>*                         fSegment;
-       const uint32_t*                                                         fIndirectTable;
-       std::vector<BaseAtom*>                                          fAtoms;
-       AddrToAtomMap                                                           fAddrToAtom;
-       AddrToAtomMap                                                           fAddrToAbsoluteAtom;
-       std::vector<class AnonymousAtom<A>*>            fLocalNonLazys;
-       std::vector<class AnonymousAtom<A>*>            fAtomsPendingAName;
-       std::set<const macho_section<P>*>                       fSectionsWithAtomsPendingAName;
-       std::vector<const char*>                                        fDtraceProviderInfo;
-       ObjectFile::Reader::DebugInfoKind                       fDebugInfo;
-       bool                                                                            fHasUUID;
-       const macho_section<P>*                                         fehFrameSection;
-       const macho_section<P>*                                         fUTF16Section;
-       std::set<BaseAtom*>                                                     fLSDAAtoms;
-       const macho_section<P>*                                         fDwarfDebugInfoSect;
-       const macho_section<P>*                                         fDwarfDebugAbbrevSect;
-       const macho_section<P>*                                         fDwarfDebugLineSect;
-       const macho_section<P>*                                         fDwarfDebugStringSect;
-       const char*                                                                     fDwarfTranslationUnitDir;
-       const char*                                                                     fDwarfTranslationUnitFile;
-       std::map<uint32_t,const char*>                          fDwarfIndexToFile;
-       std::vector<Stab>                                                       fStabs;
-       std::vector<FDE_Atom_Info>                                      fFDEInfos;
-       std::vector<CIE_Atom_Info>                                      fCIEInfos;
-       bool                                                                            fAppleObjc;
-       bool                                                                            fHasDTraceProbes;
-       bool                                                                            fHaveIndirectSymbols;
-       bool                                                                            fReplacementClasses;
-       bool                                                                            fHasLongBranchStubs;
-       ObjectFile::Reader::ObjcConstraint                      fObjConstraint;
-       uint32_t                                    fCpuConstraint;
-       const macho_section<P>*                                         fSectionsStart;
-       const macho_section<P>*                                         fSectionsEnd;
-       OAS                                                                                     fObjectAddressSpace;
-};
-
-template <typename A>
-Reader<A>::Reader(const uint8_t* fileContent, const char* path, time_t modTime, const ObjectFile::ReaderOptions& options, uint32_t ordinalBase)
-       : fPath(strdup(path)), fModTime(modTime), fOrdinalBase(ordinalBase), fOptions(options), fHeader((const macho_header<P>*)fileContent),
-        fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fSegment(NULL), fIndirectTable(NULL),
-        fDebugInfo(kDebugInfoNone), fHasUUID(false), fehFrameSection(NULL), fUTF16Section(NULL),
-        fDwarfDebugInfoSect(NULL), fDwarfDebugAbbrevSect(NULL), fDwarfDebugLineSect(NULL),
-         fDwarfTranslationUnitDir(NULL), fDwarfTranslationUnitFile(NULL), fAppleObjc(false), fHasDTraceProbes(false),
-         fHaveIndirectSymbols(false), fReplacementClasses(false), fHasLongBranchStubs(false),
-         fObjConstraint(ObjectFile::Reader::kObjcNone), fCpuConstraint(ObjectFile::Reader::kCpuAny),
-         fSectionsStart(NULL), fSectionsEnd(NULL), fObjectAddressSpace(*this)
-{
-       // sanity check
-       if ( ! validFile(fileContent, false, 0) )
-               throw "not a valid mach-o object file";
-
-       Reference<A>::fgForFinalLinkedImage = options.fForFinalLinkedImage;
-
-       // write out path for -t or -whatsloaded option
-       if ( options.fLogObjectFiles || options.fLogAllFiles )
-               printf("%s\n", path);
-
-       // cache intersting pointers
-       const macho_header<P>* header = (const macho_header<P>*)fileContent;
-       this->setCpuConstraint(header->cpusubtype());
-       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;
-       uint32_t undefinedStartIndex = 0;
-       uint32_t undefinedEndIndex = 0;
-       for (uint32_t i = 0; i < cmd_count; ++i) {
-               switch (cmd->cmd()) {
-                   case LC_SYMTAB:
-                               {
-                                       const macho_symtab_command<P>* symtab = (macho_symtab_command<P>*)cmd;
-                                       fSymbolCount = symtab->nsyms();
-                                       fSymbols = (const macho_nlist<P>*)((char*)header + symtab->symoff());
-                                       fStrings = (char*)header + symtab->stroff();
-                                       if ( undefinedEndIndex == 0 ) {
-                                               undefinedStartIndex = 0;
-                                               undefinedEndIndex = symtab->nsyms();
-                                       }
-                               }
-                               break;
-                       case LC_DYSYMTAB:
-                               {
-                                       const macho_dysymtab_command<P>* dsymtab = (struct macho_dysymtab_command<P>*)cmd;
-                                       fIndirectTable = (uint32_t*)((char*)fHeader + dsymtab->indirectsymoff());
-                                       undefinedStartIndex = dsymtab->iundefsym();
-                                       undefinedEndIndex = undefinedStartIndex + dsymtab->nundefsym();
-                               }
-                               break;
-                   case LC_UUID:
-                               fHasUUID = true;
-                               break;
-
-                       default:
-                               if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
-                                       fSegment = (macho_segment_command<P>*)cmd;
-                               }
-                               break;
-               }
-               cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
-               if ( cmd > cmdsEnd )
-                       throwf("malformed dylb, load command #%d is outside size of load commands in %s", i, path);
-       }
-
-       // if there are no load commands, then this file has no content, so no atoms
-       if ( header->ncmds() < 1 )
-               return;
-
-       fSectionsStart = (macho_section<P>*)((char*)fSegment + sizeof(macho_segment_command<P>));
-       fSectionsEnd = &fSectionsStart[fSegment->nsects()];
-
-       // inital guess for number of atoms
-       fAtoms.reserve(fSymbolCount);
-
-       // if there is an __eh_frame section, decode it into chunks to get atoms in that
-       // section as well as division points for functions in __text
-       for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
-               if ( (strcmp(sect->sectname(), "__eh_frame") == 0) && (strcmp(sect->segname(), "__TEXT") == 0) ) {
-                       fehFrameSection = sect;
-                       const char* msg = libunwind::CFI_Parser<ObjectFileAddressSpace<A> >::getCFIs(fObjectAddressSpace, sect->addr(), 
-                                                                                                                                                                               sect->size(), fFDEInfos, fCIEInfos);
-                       if ( msg != NULL ) {
-                               throwf("malformed __eh_frame section: %s", msg);
-                       }
-                       else {
-                               //fprintf(stderr, "%lu CIEs, %lu FDEs\n", fCIEInfos.size(), fFDEInfos.size());
-                               // add anonymous atoms for each CIE
-                               for (typename std::vector<CIE_Atom_Info>::const_iterator it = fCIEInfos.begin(); it != fCIEInfos.end(); ++it) {
-                                       AnonymousAtom<A>* cieAtom = new AnonymousAtom<A>(*this, sect, it->cieAddress, 1);
-                                       fAtoms.push_back(cieAtom);
-                                       fAddrToAtom[it->cieAddress] = cieAtom;
-                               }
-                               // add anonymous atoms for each FDE and LSDA
-                               for (typename std::vector<FDE_Atom_Info>::const_iterator it = fFDEInfos.begin(); it != fFDEInfos.end(); ++it) {
-                                       //fprintf(stderr, "fdeAddress=0x%08llX, lsdaAddr=0x%08llX, funcAddr=0x%08llX\n", (uint64_t)it->fdeAddress, (uint64_t)it->lsda.address,  (uint64_t)it->function.address);
-                                       AnonymousAtom<A>* fdeAtom = new AnonymousAtom<A>(*this, sect, it->fdeAddress, 0);
-                                       fAtoms.push_back(fdeAtom);
-                                       fAddrToAtom[it->fdeAddress] = fdeAtom;
-                                       if ( it->lsda.address != 0 ) {
-                                               AnonymousAtom<A>* lsdaAtom = new AnonymousAtom<A>(*this, getSectionForAddress(it->lsda.address), it->lsda.address, 0); 
-                                               fAtoms.push_back(lsdaAtom);
-                                               fAddrToAtom[it->lsda.address] = lsdaAtom;
-                                               fLSDAAtoms.insert(lsdaAtom);
-                                       }
-                               }
-                       }
-               }
-               else if ( (strcmp(sect->sectname(), "__ustring") == 0) && (strcmp(sect->segname(), "__TEXT") == 0) && (sect->size() != 0) ) {
-                       // if there is a __ustring section parse it into atoms
-                       fUTF16Section = sect;
-                       // first find all cleave points 
-                       const uint16_t* words = (uint16_t*)((char*)(fHeader) + fUTF16Section->offset());
-                       unsigned int wordCount = fUTF16Section->size()/2;
-                       std::vector<pint_t> utf16Addreses;
-                       bool inString = false;
-                       for (unsigned int i=0; i < wordCount; ++i) {
-                               if ( inString ) {
-                                       if ( words[i] == 0x0000 ) {
-                                               inString = false;
-                                       }
-                               }
-                               else {
-                                       if ( words[i] == 0x0000 ) {
-                                               // skip over zero padding
-                                       }
-                                       else {
-                                               inString = true;
-                                               utf16Addreses.push_back(fUTF16Section->addr() + i*2);
-                                       }
-                               }
-                       }
-                       utf16Addreses.push_back(fUTF16Section->addr() + sect->size());
-                       // build map of symbols
-                       std::map<pint_t, const macho_nlist<P>* > symbolMap;
-                       for (int i=fSymbolCount-1; i >= 0 ; --i) {
-                               const macho_nlist<P>& sym = fSymbols[i];
-                               if ( (sym.n_type() & N_STAB) == 0 ) {
-                                       uint8_t type =  (sym.n_type() & N_TYPE);
-                                       if ( type == N_SECT ) {
-                                               if ( &fSectionsStart[sym.n_sect()-1] == fUTF16Section ) {
-                                                       // rdar://problem/7429384 don't coalesce UTF16 strings unless label starts with ___utf16_string
-                                                       if ( strncmp(&fStrings[sym.n_strx()], "___utf16_string", 15) != 0 ) {
-                                                               symbolMap[sym.n_value()] = &sym;
-                                                               // <rdar://problem/7516793> if this symbol is a string of just 0x0000, it may not be in utf16Addreses
-                                                               if ( words[(sym.n_value() - sect->addr())/2] == 0x0000 ) {
-                                                                       for(typename std::vector<pint_t>::iterator sit=utf16Addreses.begin(); sit != utf16Addreses.end(); ++sit) {
-                                                                               if ( *sit == sym.n_value() ) {
-                                                                                       // already in utf16Addreses
-                                                                                       break;
-                                                                               }
-                                                                               if ( *sit > sym.n_value() ) {
-                                                                                       // need to insert
-                                                                                       utf16Addreses.insert(sit, sym.n_value());
-                                                                                       break;
-                                                                               }
-                                                                       }
-                                                               }
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-                       // make atom for each string
-                       for(int i=utf16Addreses.size()-2; i >=0 ; --i) {
-                               pint_t size = utf16Addreses[i+1] - utf16Addreses[i];
-                               typename std::map<pint_t, const macho_nlist<P>* >::iterator pos = symbolMap.find(utf16Addreses[i]);
-                               if ( pos == symbolMap.end() ) {
-                                       AnonymousAtom<A>* strAtom = new AnonymousAtom<A>(*this, fUTF16Section, utf16Addreses[i], size);
-                                       fAtoms.push_back(strAtom);
-                                       fAddrToAtom[utf16Addreses[i]] = strAtom;
-                               }
-                               else {
-                                       SymbolAtom<A>* newAtom = new SymbolAtom<A>(*this, pos->second, fUTF16Section);
-                                       fAtoms.push_back(newAtom);
-                                       fAddrToAtom[utf16Addreses[i]] = newAtom;
-                                       newAtom->setSize(size);
-                               }
-                       }
-               }
-       }
-
-
-       // add all atoms that have entries in symbol table
-       BaseAtom* sectionEndAtoms[fSegment->nsects()];
-       for (unsigned int i=0; i < fSegment->nsects(); ++i)
-               sectionEndAtoms[i] = NULL;
-       for (int i=fSymbolCount-1; i >= 0 ; --i) {
-               // walk backwards through symbol table so globals are see before locals, otherwise a local alias would beome the real name
-               const macho_nlist<P>& sym = fSymbols[i];
-               if ( (sym.n_type() & N_STAB) == 0 ) {
-                       uint8_t type =  (sym.n_type() & N_TYPE);
-                       if ( type == N_SECT ) {
-                               const macho_section<P>* section = &fSectionsStart[sym.n_sect()-1];
-                               const pint_t sectionStartAddr = section->addr();
-                               const pint_t sectionEndAddr = sectionStartAddr + section->size();
-                               bool suppress = false;
-                               // ignore atoms in debugger sections 
-                               if ( (section->flags() & S_ATTR_DEBUG) == 0 ) {
-                                       if ( strncmp(&fStrings[sym.n_strx()], "__dtrace_probe$", 15) == 0 ) {
-                                               // ignore dtrace probe labels 
-                                               fHasDTraceProbes = true;
-                                       }
-                                       else if ( fStrings[sym.n_strx()] == 'L' ) {
-                                               // ignore L labels, <rdar://problem/3962731>
-                                       }
-                                       else if ( section == fehFrameSection ) {
-                                               // ignore labels in __eh_frame section
-                                       }
-                                       else if ( section == fUTF16Section ) {
-                                               // ignore labels in __ustring section
-                                       }
-                                       else {
-                                               // ignore labels for atoms in other sections
-                                               switch ( section->flags() & SECTION_TYPE ) {
-                                                       case S_REGULAR:
-                                                               if ( (sym.n_desc() & N_WEAK_DEF) && strcmp(section->sectname(), "__picsymbolstub1__TEXT") == 0 )
-                                                                       suppress = true; // ignore stubs in crt1.o built by old ld64 that was missing S_SYMBOL_STUBS
-                                                       case S_ZEROFILL:
-                                                       case S_COALESCED:
-                                                       case S_4BYTE_LITERALS:
-                                                       case S_8BYTE_LITERALS:
-                                                       case S_16BYTE_LITERALS:
-                                                       case S_CSTRING_LITERALS:
-                                                               {
-                                                                       BaseAtom* newAtom;
-                                                                       typename AddrToAtomMap::iterator pos = fAddrToAtom.find(sym.n_value());
-                                                                       if ( (pos != fAddrToAtom.end()) && (pos->second->getSectionRecord() == section) ) {
-                                                                               if ( fLSDAAtoms.count(pos->second) != 0 ) {
-                                                                                       // already have LSDA atom from for this address, ignore compiler's label
-                                                                                       suppress = true;
-                                                                                       break;
-                                                                               }
-                                                                               else {
-                                                                                       // another label to an existing address in the same section, make this an alias
-                                                                                       newAtom = new SymbolAliasAtom<A>(&fStrings[sym.n_strx()], &sym, *pos->second);
-                                                                               }
-                                                                       }
-                                                                       else {
-                                                                               if ( sym.n_value() == sectionEndAddr ) {
-                                                                                       // Symbol address is at end of section.  This can interfere
-                                                                                       // with a symbol at the start of the next section, so don't
-                                                                                       // add to fAddrToAtom. But do track in sectionEndAtoms so we
-                                                                                       // still make aliases if there are duplicates.
-                                                                                       if ( sectionEndAtoms[sym.n_sect()-1] == NULL ) {
-                                                                                               newAtom = new SymbolAtom<A>(*this, &sym, section);
-                                                                                               sectionEndAtoms[sym.n_sect()-1] = newAtom;
-                                                                                               // if this is a zero length section, so add to fAddrToAtom
-                                                                                               if ( sym.n_value() == sectionStartAddr )
-                                                                                                       fAddrToAtom[newAtom->getObjectAddress()] = newAtom;
-                                                                                       }
-                                                                                       else {
-                                                                                               newAtom = new SymbolAliasAtom<A>(&fStrings[sym.n_strx()], &sym, *sectionEndAtoms[sym.n_sect()-1]);
-                                                                                       }
-                                                                               }
-                                                                               else {
-                                                                                       // make SymbolAtom atom for this address
-                                                                                       newAtom = new SymbolAtom<A>(*this, &sym, section);
-                                                                                       fAddrToAtom[newAtom->getObjectAddress()] = newAtom;
-                                                                               }
-                                                                       }
-                                                                       if ( ! suppress )
-                                                                               fAtoms.push_back(newAtom);
-                                                                       }
-                                                               break;
-                                                       case S_SYMBOL_STUBS:
-                                                       case S_LAZY_SYMBOL_POINTERS:
-                                                       case S_NON_LAZY_SYMBOL_POINTERS:
-                                                               // ignore symboled stubs produces by old ld64
-                                                               break;
-                                                       default:
-                                                               warning("symbol %s found in unsupported section in %s",
-                                                                       &fStrings[sym.n_strx()], this->getPath());
-                                               }
-                                       }
-                               }
-                       }
-                       else if ( (type == N_UNDF) && (sym.n_value() != 0) ) {
-                               fAtoms.push_back(new TentativeAtom<A>(*this, &sym));
-                       }
-                       else if ( (type == N_UNDF) && (sym.n_value() == 0) ) {
-                               const char* symName = &fStrings[sym.n_strx()];
-                               if ( strncmp(symName, "section$start$", 14) == 0) 
-                                       fAtoms.push_back(new SectionBoundaryAtom<A>(*this, true, symName, &symName[14]));
-                               else if ( strncmp(symName, "section$end$", 12) == 0) 
-                                       fAtoms.push_back(new SectionBoundaryAtom<A>(*this, false, symName, &symName[12]));
-                       }
-                       else if ( type == N_ABS ) {
-                               const char* symName = &fStrings[sym.n_strx()];
-                               if ( strncmp(symName, ".objc_class_name_", 17) == 0 ) {
-                                       // ignore .objc_class_name_* symbols 
-                                       fAppleObjc = true;
-                               }
-                               else if ( strcmp(&symName[strlen(symName)-3], ".eh") == 0 ) {
-                                       // ignore empty *.eh symbols
-                               }
-                               else {
-                                       BaseAtom* abAtom = new AbsoluteAtom<A>(*this, &sym);
-                                       fAtoms.push_back(abAtom);
-                                       fAddrToAbsoluteAtom[sym.n_value()] = abAtom;
-                               }
-                       }
-                       else if ( type == N_INDR ) {
-                               fHaveIndirectSymbols = true;
-                       }
-               }
-       }
-
-       // add anonymous atoms for any functions (as determined by dwarf unwind) have no symbol names
-       if ( fehFrameSection != NULL ) {
-               for (typename std::vector<FDE_Atom_Info>::const_iterator it = fFDEInfos.begin(); it != fFDEInfos.end(); ++it) {
-                       // add if not already an atom at that address
-                       if ( fAddrToAtom.find(it->function.address) == fAddrToAtom.end() ) {
-                               AnonymousAtom<A>* funcAtom = new AnonymousAtom<A>(*this, getSectionForAddress(it->function.address), it->function.address, 0);
-                               fAtoms.push_back(funcAtom);
-                               fAddrToAtom[it->function.address] = funcAtom;
-                               // even though we've made a new atom, be conservative and make sure they lay out together
-                               if ( canScatterAtoms() ) {
-                                       AtomAndOffset prev = findAtomAndOffset(it->function.address-1);
-                                       if ( prev.atom != NULL ) {
-                                               if ( ((BaseAtom*)(prev.atom))->getSectionRecord() == funcAtom->getSectionRecord() )
-                                                       new Reference<A>(A::kFollowOn, prev, AtomAndOffset(funcAtom));
-                                       }
-                               }
-                       }
-               }
-       }
-
-
-       // add all fixed size anonymous atoms from special sections
-       for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
-               pint_t atomSize = 0;
-               uint8_t type (sect->flags() & SECTION_TYPE);
-               validSectionType(type);
-               bool suppress = false;
-               switch ( type ) {
-                       case S_SYMBOL_STUBS:
-                               suppress = true;
-                               atomSize = sect->reserved2();
-                               break;
-                       case S_LAZY_SYMBOL_POINTERS:
-                               suppress = true;
-                               atomSize = sizeof(pint_t);
-                               break;
-                       case S_NON_LAZY_SYMBOL_POINTERS:
-                       case S_LITERAL_POINTERS:
-                       case S_MOD_INIT_FUNC_POINTERS:
-                       case S_MOD_TERM_FUNC_POINTERS:
-                               atomSize = sizeof(pint_t);
-                               break;
-                       case S_INTERPOSING:
-                               atomSize = sizeof(pint_t)*2;
-                               break;
-                       case S_4BYTE_LITERALS:
-                               atomSize = 4;
-                               break;
-                       case S_8BYTE_LITERALS:
-                               atomSize = 8;
-                               break;
-                       case S_16BYTE_LITERALS:
-                               atomSize = 16;
-                               break;
-                       case S_REGULAR:
-                               // special case ObjC classes to synthesize .objc_class_name_* symbols
-                               if ( (strcmp(sect->sectname(), "__class") == 0) && (strcmp(sect->segname(), "__OBJC") == 0) && fAppleObjc ) {
-                                       // gcc sometimes over aligns class structure
-                                       uint32_t align = 1 << sect->align();
-                                       atomSize = ((12 * sizeof(pint_t)) + align-1) & (-align);
-                               }
-                               // get objc Garbage Collection info
-                               else if ( ((strcmp(sect->sectname(), "__image_info") == 0) && (strcmp(sect->segname(), "__OBJC") == 0))
-                                          || ((strncmp(sect->sectname(), "__objc_imageinfo", 16) == 0) && (strcmp(sect->segname(), "__DATA") == 0)) ) {
-                                       //      struct objc_image_info  {
-                                       //              uint32_t        version;        // initially 0
-                                       //              uint32_t        flags;
-                                       //      };
-                                       // #define OBJC_IMAGE_SUPPORTS_GC   2
-                                       // #define OBJC_IMAGE_GC_ONLY       4
-                                       //
-                                       const uint32_t* contents = (uint32_t*)(((char*)fHeader) + sect->offset());
-                                       if ( (sect->size() >= 8) && (contents[0] == 0) ) {
-                                               uint32_t flags = E::get32(contents[1]);
-                                               if ( (flags & 4) == 4 )
-                                                       fObjConstraint = ObjectFile::Reader::kObjcGC;
-                                               else if ( (flags & 2) == 2 )
-                                                       fObjConstraint = ObjectFile::Reader::kObjcRetainReleaseOrGC;
-                                               else
-                                                       fObjConstraint = ObjectFile::Reader::kObjcRetainRelease;
-                                               if ( (flags & 1) == 1 )
-                                                       fReplacementClasses = true;
-                                               // don't make atom for this section
-                                               atomSize = sect->size();
-                                               suppress = true;
-                                       }
-                                       else {
-                                               warning("can't parse __OBJC/__image_info section in %s", fPath);
-                                       }
-                               }
-                               // special case constant NS/CFString literals and make an atom out of each one
-                               else if ((strcmp(sect->sectname(), "__cfstring") == 0) && (strcmp(sect->segname(), "__DATA") == 0)) {
-                                       atomSize = 4 * sizeof(pint_t);
-                               }
-                               // special case class reference sections
-                               else if ( (strncmp(sect->sectname(), "__objc_classrefs", 16) == 0) && (strcmp(sect->segname(), "__DATA") == 0) ) {
-                                       atomSize = sizeof(pint_t);;
-                               }
-                               break;
-               }
-               if ( atomSize != 0 ) {
-                       for(pint_t sectOffset=0; sectOffset < sect->size(); sectOffset += atomSize) {
-                               pint_t atomAddr = sect->addr() + sectOffset;
-                               // add if not already an atom at that address
-                               if ( fAddrToAtom.find(atomAddr) == fAddrToAtom.end() ) {
-                                       AnonymousAtom<A>* newAtom = new AnonymousAtom<A>(*this, sect, atomAddr, atomSize);
-                                       if ( !suppress )
-                                               fAtoms.push_back(newAtom);
-                                       fAddrToAtom[atomAddr] = newAtom->redirectTo();
-                               }
-                       }
-               }
-       }
-
-       // add all c-string anonymous atoms
-       for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
-               if ( ((sect->flags() & SECTION_TYPE) == S_CSTRING_LITERALS) || strcmp(sect->sectname(), "__cstring") == 0 ) {
-                       uint32_t stringLen;
-                       pint_t stringAddr;
-                       BaseAtom* mostAlignedEmptyString = NULL;
-                       uint32_t mostAlignedEmptyStringTrailingZeros = 0;
-                       std::vector<std::pair<pint_t,BaseAtom*> > emptyStrings;
-                       for(pint_t sectOffset=0; sectOffset < sect->size(); sectOffset += stringLen) {
-                               stringAddr = sect->addr() + sectOffset;
-                               stringLen  = strlen((char*)(fHeader) + sect->offset() + sectOffset) + 1;
-                               // add if not already a non-zero length atom at that address
-                               typename AddrToAtomMap::iterator pos = fAddrToAtom.find(stringAddr);
-                               if ( (pos == fAddrToAtom.end()) || (pos->second->getSize() == 0) ) {
-                                       BaseAtom* newAtom = new AnonymousAtom<A>(*this, sect, stringAddr, stringLen);
-                                       if ( stringLen == 1 ) {
-                                               // because of padding it may look like there are lots of empty strings, keep track of all
-                                               emptyStrings.push_back(std::make_pair<pint_t,BaseAtom*>(stringAddr, newAtom));
-                                               // record empty string with greatest alignment requirement
-                                               uint32_t stringAddrTrailingZeros = (stringAddr==0) ? sect->align() : __builtin_ctz(stringAddr);
-                                               if ( (mostAlignedEmptyString == NULL) 
-                                                       || ( stringAddrTrailingZeros > mostAlignedEmptyStringTrailingZeros) ) {
-                                                       mostAlignedEmptyString = newAtom;
-                                                       mostAlignedEmptyStringTrailingZeros = stringAddrTrailingZeros;
-                                               }
-                                       }
-                                       else {
-                                               fAtoms.push_back(newAtom);
-                                               fAddrToAtom[stringAddr] = newAtom;
-                                       }
-                               }
-                       }
-                       // map all uses of empty strings to the most aligned one
-                       if ( mostAlignedEmptyString != NULL ) {
-                               // make most aligned atom a real atom
-                               fAtoms.push_back(mostAlignedEmptyString);
-                               // map all other empty atoms to this one
-                               for (typename std::vector<std::pair<pint_t,BaseAtom*> >::iterator it=emptyStrings.begin(); it != emptyStrings.end(); it++) {
-                                       fAddrToAtom[it->first] = mostAlignedEmptyString;
-                               }
-                       }
-               }
-       }
-
-       // sort all atoms so far by address and section
-       std::sort(fAtoms.begin(), fAtoms.end(), BaseAtomSorter());
-
-       //fprintf(stderr, "sorted atoms:\n");
-       //for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) 
-       //      fprintf(stderr, "0x%08llX %s\n", (*it)->getObjectAddress(), (*it)->getDisplayName());
-
-       // create atoms to cover any non-debug ranges not handled above
-       for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
-               pint_t sectionStartAddr = sect->addr();
-               pint_t sectionEndAddr   = sect->addr() + sect->size();
-               // don't set follow-on atoms in __eh_frame section
-               const bool setFollowOnAtom = !canScatterAtoms() && (sect != fehFrameSection);
-               if ( sect->size() != 0 ) {
-                       // ignore dwarf sections.  If ld every supports processing dwarf, this logic will need to change
-                       if ( (sect->flags() & S_ATTR_DEBUG) != 0 ) {
-                               fDebugInfo = kDebugInfoDwarf;
-                               if ( strcmp(sect->sectname(), "__debug_info") == 0 )
-                                       fDwarfDebugInfoSect = sect;
-                               else if ( strcmp(sect->sectname(), "__debug_abbrev") == 0 )
-                                       fDwarfDebugAbbrevSect = sect;
-                               else if ( strcmp(sect->sectname(), "__debug_line") == 0 )
-                                       fDwarfDebugLineSect = sect;
-                               else if ( strcmp(sect->sectname(), "__debug_str") == 0 )
-                                       fDwarfDebugStringSect = sect;
-                       }
-                       else {
-                               if ( strcmp(sect->segname(), "__DWARFA") == 0 ) {
-                                       throw "object file contains old DWARF debug info - rebuild with newer compiler";
-                               }
-                               uint8_t type (sect->flags() & SECTION_TYPE);
-                               switch ( type ) {
-                                       case S_REGULAR:
-                                       case S_ZEROFILL:
-                                       case S_COALESCED:
-                                               // if there is not an atom already at the start of this section, add an anonymous one
-                                               pint_t previousAtomAddr = 0;
-                                               BaseAtom* previousAtom = NULL;
-                                               if ( fAddrToAtom.find(sectionStartAddr) == fAddrToAtom.end() ) {
-                                                       BaseAtom* newAtom = new AnonymousAtom<A>(*this, sect, sect->addr(), 0);
-                                                       fAddrToAtom[sect->addr()] = newAtom;
-                                                       fAtoms.push_back(newAtom);
-                                                       previousAtomAddr = sectionStartAddr;
-                                                       previousAtom = newAtom;
-                                                       std::sort(fAtoms.begin(), fAtoms.end(), BaseAtomSorter());
-                                               }
-                                               // calculate size of all atoms in this section and add follow-on references
-                                               for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) {
-                                                       BaseAtom* atom = (BaseAtom*)(*it);
-                                                       pint_t atomAddr = atom->getObjectAddress();
-                                                       if ( atom->getSectionRecord() == sect ) {
-                                                               //fprintf(stderr, "addr=0x%08llX, atom=%s\n", (uint64_t)atomAddr, atom->getDisplayName());
-                                                               if ( (previousAtom != NULL) && (previousAtomAddr != atomAddr) ) {
-                                                                       previousAtom->setSize(atomAddr - previousAtomAddr);
-                                                                       if ( setFollowOnAtom && (atom != previousAtom) )
-                                                                               new Reference<A>(A::kFollowOn, AtomAndOffset(previousAtom), AtomAndOffset(atom));
-                                                               }
-                                                               previousAtomAddr = atomAddr;
-                                                               previousAtom = atom;
-                                                       } 
-                                               }
-                                               if ( previousAtom != NULL ) {
-                                                       // set last atom in section
-                                                       previousAtom->setSize(sectionEndAddr - previousAtomAddr);
-                                               }
-                                               break;
-                               }
-                       }
-               }
-       }
-
-       // check for object file that defines no objc classes, but uses objc classes
-       // check for dtrace provider info
-       for (uint32_t i=undefinedStartIndex; i < undefinedEndIndex; ++i) {
-               const macho_nlist<P>& sym = fSymbols[i];
-               if ( (sym.n_type() & N_STAB) == 0 ) {
-                       if ( (sym.n_type() & N_TYPE) == N_UNDF ) {
-                               const char* undefinedName = &fStrings[sym.n_strx()];
-                               if ( !fAppleObjc && (strncmp(undefinedName, ".objc_class_name_", 17) == 0) ) {
-                                       fAppleObjc = true;
-                               }
-                               else if ( strncmp(undefinedName, "___dtrace_", 10) == 0 ) {
-                                       if ( strchr(undefinedName, '$') != NULL  ) {
-                                               if ( (strncmp(&undefinedName[10], "probe$", 6) != 0) && (strncmp(&undefinedName[10], "isenabled$", 10) != 0) ) {
-                                                       // any undefined starting with __dtrace_*$ that is not ___dtrace_probe$* or ___dtrace_isenabled$*
-                                                       // is extra provider info
-                                                       fDtraceProviderInfo.push_back(undefinedName);
-                                               }
-                                       }
-                               }
-                       }
-               }
-       }
-       
-       // add relocation based references to sections that have atoms with pending names
-       for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
-               if ( fSectionsWithAtomsPendingAName.count(sect) != 0 )
-                       addReferencesForSection(sect);
-       }
-       
-       // update any anonymous atoms that need references built in order to name themselves
-       for (typename std::vector<AnonymousAtom<A>*>::iterator it=fAtomsPendingAName.begin(); it != fAtomsPendingAName.end(); it++) {
-               (*it)->resolveName();
-       }
-
-       // add relocation based references to other sections
-       for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
-               if ( fSectionsWithAtomsPendingAName.count(sect) == 0 )
-                       addReferencesForSection(sect);
-       }
-
-       // add objective-c references
-       if ( fAppleObjc ) {
-               for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
-                       if ( (strcmp(sect->sectname(), "__cls_refs") == 0) && (strcmp(sect->segname(), "__OBJC") == 0) ) {
-                               for (uint32_t offset = 0; offset < sect->size(); offset += sizeof(pint_t)) {
-                                       AtomAndOffset ao = this->findAtomAndOffset(sect->addr()+offset);
-                                       ObjectFile::Reference* classRef = ao.atom->getReferences()[0];
-                                       if ( classRef->getFixUpOffset() == 0 ) {
-                                               const char* classStr = classRef->getTargetName();
-                                               if ( strncmp(classStr, "cstring=", 8) == 0 ) {
-                                                       const char* className;
-                                                       asprintf((char**)&className, ".objc_class_name_%s", &classStr[8]);
-                                                       new Reference<A>(A::kNoFixUp, ao, className, 0);
-                                               }
-                                       }
-                               }
-                       }
-               }
-       }
-
-       // add direct references to local non-lazy-pointers, can do this now that all atoms are constructed
-       for (typename std::vector<AnonymousAtom<A>*>::iterator it=fLocalNonLazys.begin(); it != fLocalNonLazys.end(); it++) {
-               AnonymousAtom<A>* localNonLazy = *it;
-               uint32_t fileOffset = localNonLazy->fSection->offset() - localNonLazy->fSection->addr() + localNonLazy->fAddress;
-               pint_t nonLazyPtrValue = P::getP(*((pint_t*)((char*)(fHeader)+fileOffset)));
-               makeReference(A::kPointer, localNonLazy->fAddress, nonLazyPtrValue);
-       }
-       
-
-       // add personality references to CIEs
-       for (typename std::vector<CIE_Atom_Info>::const_iterator it = fCIEInfos.begin(); it != fCIEInfos.end(); ++it) {
-               if ( it->personality.offsetInFDE != 0 )
-                       addCiePersonalityReference(fAddrToAtom[it->cieAddress], it->personality.offsetInFDE, it->personality.encodingOfAddress);
-       }
-
-       // add all references for FDEs, including implicit group references
-       for (typename std::vector<FDE_Atom_Info>::const_iterator it = fFDEInfos.begin(); it != fFDEInfos.end(); ++it) {
-               AtomAndOffset funcAO = this->findAtomAndOffset(it->function.address);
-               if ( funcAO.offset != 0 )
-                       warning("FDE does not point to start of function %s\n", funcAO.atom->getDisplayName());
-               AtomAndOffset fdeAO = this->findAtomAndOffset(it->fdeAddress);
-               if ( fdeAO.offset != 0 )
-                       warning("FDE does start its own atom %s\n", funcAO.atom->getDisplayName());
-               AtomAndOffset cieAO = this->findAtomAndOffset(it->cie.address);
-               if ( cieAO.offset != 0 )
-                       warning("CIE does start its own atom %s\n", cieAO.atom->getDisplayName());
-               AtomAndOffset lsdaAO;
-               if ( it->lsda.address != 0 ) {
-                       lsdaAO = this->findAtomAndOffset(it->lsda.address);
-                       if ( lsdaAO.offset != 0 )
-                               warning("LSDA does start its own atom %s\n", lsdaAO.atom->getDisplayName());
-               }
-               
-               // add reference from FDE to CIE        
-               AtomAndOffset cieInfdeAO = AtomAndOffset(fdeAO.atom, it->cie.offsetInFDE);
-               new Reference<A>(A::kPointerDiff32, cieInfdeAO, cieAO, cieInfdeAO);
-               
-               // add reference from FDE to function
-               addFdeReference(it->function.encodingOfAddress, AtomAndOffset(fdeAO.atom, it->function.offsetInFDE), funcAO);
-                               
-               // add reference from FDE to LSDA
-               if ( it->lsda.address != 0 ) {
-                       addFdeReference(it->lsda.encodingOfAddress, AtomAndOffset(fdeAO.atom, it->lsda.offsetInFDE), lsdaAO);
-               }
-               
-               // FDE is in group lead by function atom
-               new Reference<A>(A::kGroupSubordinate, funcAO, fdeAO);
-               
-               // LSDA is in group lead by function atom
-               if ( it->lsda.address != 0 ) {
-                       new Reference<A>(A::kGroupSubordinate, funcAO, lsdaAO);
-                       // add back reference from LSDA to owning function
-                       new Reference<A>(A::kNoFixUp, lsdaAO, funcAO);
-               }
-
-               // compute compact encoding for this FDE
-               if ( fOptions.fAddCompactUnwindEncoding ) {
-                       ((BaseAtom*)(funcAO.atom))->setCompactUnwindEncoding(it->fdeAddress);
-                       // add reference from function atom to personality function
-                       // the only reference a CIE can have is the reference to the personality function
-                       std::vector<class ObjectFile::Reference*>& cieRefs = cieAO.atom->getReferences();
-                       if ( cieRefs.size() == 1 ) {
-                               new Reference<A>((typename A::ReferenceKinds)((BaseAtom*)(funcAO.atom))->getPersonalityReferenceKind(), 
-                                                                       funcAO, cieRefs[0]->getTargetName(), 0);
-                       }
-               }
-       }
-
-       // add command line aliases
-       for(std::vector<ObjectFile::ReaderOptions::AliasPair>::const_iterator it = fOptions.fAliases.begin(); it != fOptions.fAliases.end(); ++it) { 
-               BaseAtom* target = this->findAtomByName(it->realName);
-               if ( (target != NULL) && target->getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn )
-                       fAtoms.push_back(new SymbolAliasAtom<A>(it->alias, NULL, *target));
-       }
-
-       // add dtrace probe locations
-       if ( fHasDTraceProbes ) {
-               for (uint32_t i=0; i < fSymbolCount; ++i) {
-                       const macho_nlist<P>& sym = fSymbols[i];
-                       if ( (sym.n_type() & N_STAB) == 0 ) {
-                               if ( (sym.n_type() & N_TYPE) == N_SECT ) {
-                                       const char* symbolName = &fStrings[sym.n_strx()];
-                                       if ( strncmp(symbolName, "__dtrace_probe$", 15) == 0 ) {
-                                               //fprintf(stderr, "adding dtrace probe at 0x%08llX %s\n", sym.n_value(), symbolName);
-                                               makeByNameReference(A::kDtraceProbe, sym.n_value(), symbolName, 0);
-                                       }
-                               }
-                       }
-               }
-       }
-       
-       // turn indirect symbols into SymbolAliasAtom 
-       if ( fHaveIndirectSymbols ) {
-               for (uint32_t i=0; i < fSymbolCount; ++i) {
-                       const macho_nlist<P>& sym = fSymbols[i];
-                       if ( (sym.n_type() & N_STAB) == 0 ) {
-                               if ( (sym.n_type() & N_TYPE) == N_INDR ) {
-                                       const char* aliasName = &fStrings[sym.n_strx()];
-                                       const char* targetName = &fStrings[sym.n_value()];
-                                       //fprintf(stderr, "found alias %s for %s\n", aliasName, targetName);
-                                       BaseAtom* target = this->findAtomByName(targetName);
-                                       // only currently support N_INDR based aliases to something in the same .o file 
-                                       if ( target != NULL ) {
-                                               fAtoms.push_back(new SymbolAliasAtom<A>(aliasName, &sym, *target));
-                                               //fprintf(stderr, "creating alias %s for %s\n", aliasName, targetName);
-                                       }
-                               }
-                       }
-               }
-       }
-
-       //for (typename AddrToAtomMap::iterator it=fAddrToAtom.begin(); it != fAddrToAtom.end(); it++) {
-       //      fprintf(stderr, "[0x%0X -> 0x%0llX) : %s\n", it->first, it->first+it->second->getSize(), it->second->getDisplayName());
-       //}
-
-       // add translation unit info from dwarf
-       uint64_t stmtList;
-       if ( (fDebugInfo == kDebugInfoDwarf) && (fOptions.fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone) ) {
-               // compiler sometimes emits emtpty dwarf sections when there is no debug info, skip those
-               if ( (fDwarfDebugInfoSect != NULL) && (fDwarfDebugInfoSect->size() != 0) ) {
-                       if ( !read_comp_unit(&fDwarfTranslationUnitFile, &fDwarfTranslationUnitDir, &stmtList) ) {
-                               // if can't parse dwarf, warn and give up
-                               fDwarfTranslationUnitFile = NULL;
-                               fDwarfTranslationUnitDir = NULL;
-                               warning("can't parse dwarf compilation unit info in %s", this->getPath());
-                               fDebugInfo = kDebugInfoNone;
-                       }
-               }
-       }
-
-       // add line number info to atoms from dwarf
-       if ( (fDebugInfo == kDebugInfoDwarf) && (fOptions.fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone) ) {
-               // file with just data will have no __debug_line info
-               if ( (fDwarfDebugLineSect != NULL) && (fDwarfDebugLineSect->size() != 0) && (fAddrToAtom.size() != 0)
-                       && (fDwarfDebugInfoSect != NULL) && (fDwarfDebugInfoSect->size() != 0) ) {
-                       // validate stmt_list
-                       if ( (stmtList != (uint64_t)-1) && (stmtList < fDwarfDebugLineSect->size()) ) {
-                               const uint8_t* debug_line = (uint8_t*)(fHeader) + fDwarfDebugLineSect->offset();
-                               if ( debug_line != NULL ) {
-                                       struct line_reader_data* lines = line_open(&debug_line[stmtList],
-                                                                                                                       fDwarfDebugLineSect->size() - stmtList, E::little_endian);
-                                       struct line_info result;
-                                       ObjectFile::Atom* curAtom = NULL;
-                                       uint32_t curAtomOffset = 0;
-                                       uint32_t curAtomAddress = 0;
-                                       uint32_t curAtomSize = 0;
-                                       if ( lines != NULL ) {
-                                               while ( line_next (lines, &result, line_stop_pc) ) {
-                                                       //fprintf(stderr, "curAtom=%p, result.pc=0x%llX, result.line=%llu, result.end_of_sequence=%d, curAtomAddress=0x%X, curAtomSize=0x%X\n",
-                                                       //              curAtom, result.pc, result.line, result.end_of_sequence, curAtomAddress, curAtomSize);
-                                                       // work around weird debug line table compiler generates if no functions in __text section
-                                                       if ( (curAtom == NULL) && (result.pc == 0) && result.end_of_sequence && (result.file == 1))
-                                                               continue;
-                                                       // for performance, see if in next pc is in current atom
-                                                       if ( (curAtom != NULL) && (curAtomAddress <= result.pc) && (result.pc < (curAtomAddress+curAtomSize)) ) {
-                                                               curAtomOffset = result.pc - curAtomAddress;
-                                                       }
-                                                       // or pc at end of current atom
-                                                       else if ( result.end_of_sequence && (curAtom != NULL) && (result.pc == (curAtomAddress+curAtomSize)) ) {
-                                                               curAtomOffset = result.pc - curAtomAddress;
-                                                       }
-                                                       else {
-                                                               // do slow look up of atom by address
-                                                               AtomAndOffset ao = this->findAtomAndOffset(result.pc);
-                                                               curAtom                 = ao.atom;
-                                                               if ( curAtom == NULL )
-                                                                       break; // file has line info but no functions
-                                                               if ( result.end_of_sequence && (curAtomAddress+curAtomSize < result.pc) ) {     
-                                                                       // a one line function can be returned by line_next() as one entry with pc at end of blob
-                                                                       // look for alt atom starting at end of previous atom
-                                                                       uint32_t previousEnd = curAtomAddress+curAtomSize;
-                                                                       AtomAndOffset alt = this->findAtomAndOffset(previousEnd);
-                                                                       if ( result.pc <= previousEnd - alt.offset + alt.atom->getSize() ) {
-                                                                               curAtom                 = alt.atom;
-                                                                               curAtomOffset   = alt.offset;
-                                                                               curAtomAddress  = previousEnd - alt.offset;
-                                                                               curAtomSize             = curAtom->getSize();
-                                                                       }
-                                                                       else {
-                                                                               curAtomOffset   = ao.offset;
-                                                                               curAtomAddress  = result.pc - ao.offset;
-                                                                               curAtomSize             = curAtom->getSize();
-                                                                       }
-                                                               }
-                                                               else {
-                                                                       curAtomOffset   = ao.offset;
-                                                                       curAtomAddress  = result.pc - ao.offset;
-                                                                       curAtomSize             = curAtom->getSize();
-                                                               }
-                                                       }
-                                                       const char* filename;
-                                                       std::map<uint32_t,const char*>::iterator pos = fDwarfIndexToFile.find(result.file);
-                                                       if ( pos == fDwarfIndexToFile.end() ) {
-                                                               filename = line_file(lines, result.file);
-                                                               fDwarfIndexToFile[result.file] = filename;
-                                                       }
-                                                       else {
-                                                               filename = pos->second;
-                                                       }
-                                                       ObjectFile::LineInfo info;
-                                                       info.atomOffset = curAtomOffset;
-                                                       info.fileName = filename;
-                                                       info.lineNumber = result.line;
-                                                       //fprintf(stderr, "addr=0x%08llX, line=%lld, file=%s, atom=%s, atom.size=0x%X, end=%d\n", 
-                                                       //              result.pc, result.line, filename, curAtom->getDisplayName(), curAtomSize, result.end_of_sequence);
-                                                       ((BaseAtom*)curAtom)->addLineInfo(info);
-                                                       if ( result.end_of_sequence ) {
-                                                               curAtom = NULL;
-                                                       }
-                                               }
-                                       line_free(lines);
-                                       }
-                               }
-                               else {
-                                       warning("could not parse dwarf line number info in %s", this->getPath());
-                               }
-                       }
-               }
-       }
-
-       // if no dwarf, try processing stabs debugging info
-       if ( (fDebugInfo == kDebugInfoNone) && (fOptions.fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone) ) {
-               // scan symbol table for stabs entries
-               fStabs.reserve(fSymbolCount);  // reduce re-allocations
-               BaseAtom* currentAtom = NULL;
-               pint_t currentAtomAddress = 0;
-               enum { start, inBeginEnd, inFun } state = start;
-               for (uint32_t symbolIndex = 0; symbolIndex < fSymbolCount; ++symbolIndex ) {
-                       const macho_nlist<P>* sym = &fSymbols[symbolIndex];
-                       bool useStab = true;
-                       uint8_t type = sym->n_type();
-                       const char* symString = (sym->n_strx() != 0) ? &fStrings[sym->n_strx()] : NULL;
-                       if ( (type & N_STAB) != 0 ) {
-                               fDebugInfo =  (fHasUUID ? kDebugInfoStabsUUID : kDebugInfoStabs);
-                               Stab stab;
-                               stab.atom       = NULL;
-                               stab.type       = type;
-                               stab.other      = sym->n_sect();
-                               stab.desc       = sym->n_desc();
-                               stab.value      = sym->n_value();
-                               stab.string = NULL;
-                               switch (state) {
-                                       case start:
-                                               switch (type) {
-                                                       case N_BNSYM:
-                                                               // beginning of function block
-                                                               state = inBeginEnd;
-                                                               // fall into case to lookup atom by addresss
-                                                       case N_LCSYM:
-                                                       case N_STSYM:
-                                                               currentAtomAddress = sym->n_value();
-                                                               currentAtom = (BaseAtom*)this->findAtomAndOffset(currentAtomAddress).atom;
-                                                               if ( currentAtom != NULL ) {
-                                                                       stab.atom = currentAtom;
-                                                                       stab.string = symString;
-                                                               }
-                                                               else {
-                                                                       fprintf(stderr, "can't find atom for stabs BNSYM at %08llX in %s",
-                                                                               (uint64_t)sym->n_value(), path);
-                                                               }
-                                                               break;
-                                                       case N_SO:
-                                                       case N_OSO:
-                                                       case N_OPT:
-                                                       case N_LSYM:
-                                                       case N_RSYM:
-                                                       case N_PSYM:
-                                                               // not associated with an atom, just copy
-                                                               stab.string = symString;
-                                                               break;
-                                                       case N_GSYM:
-                                                       {
-                                                               // n_value field is NOT atom address ;-(
-                                                               // need to find atom by name match
-                                                               const char* colon = strchr(symString, ':');
-                                                               if ( colon != NULL ) {
-                                                                       // build underscore leading name
-                                                                       int nameLen = colon - symString;
-                                                                       char symName[nameLen+2];
-                                                                       strlcpy(&symName[1], symString, nameLen+1);
-                                                                       symName[0] = '_';
-                                                                       symName[nameLen+1] = '\0';
-                                                                       currentAtom = findAtomByName(symName);
-                                                                       if ( currentAtom != NULL ) {
-                                                                               stab.atom = currentAtom;
-                                                                               stab.string = symString;
-                                                                       }
-                                                               }
-                                                               else {
-                                                                       // might be a debug-note without trailing :G()
-                                                                       currentAtom = findAtomByName(symString);
-                                                                       if ( currentAtom != NULL ) {
-                                                                               stab.atom = currentAtom;
-                                                                               stab.string = symString;
-                                                                       }
-                                                               }
-                                                               if ( stab.atom == NULL ) {
-                                                                       // ld_classic added bogus GSYM stabs for old style dtrace probes
-                                                                       if ( (strncmp(symString, "__dtrace_probe$", 15) != 0) )
-                                                                               warning("can't find atom for N_GSYM stabs %s in %s", symString, path);
-                                                                       useStab = false;
-                                                               }
-                                                               break;
-                                                       }
-                                                       case N_FUN:
-                                                               // old style stabs without BNSYM
-                                                               state = inFun;
-                                                               currentAtomAddress = sym->n_value();
-                                                               currentAtom = (BaseAtom*)this->findAtomAndOffset(currentAtomAddress).atom;
-                                                               if ( currentAtom != NULL ) {
-                                                                       stab.atom = currentAtom;
-                                                                       stab.string = symString;
-                                                               }
-                                                               else {
-                                                                       warning("can't find atom for stabs FUN at %08llX in %s",
-                                                                               (uint64_t)currentAtomAddress, path);
-                                                               }
-                                                               break;
-                                                       case N_SOL:
-                                                       case N_SLINE:
-                                                               stab.string = symString;
-                                                               // old stabs
-                                                               break;
-                                                       case N_BINCL:
-                                                       case N_EINCL:
-                                                       case N_EXCL:
-                                                               stab.string = symString;
-                                                               // -gfull built .o file
-                                                               break;
-                                                       default:
-                                                               warning("unknown stabs type 0x%X in %s", type, path);
-                                               }
-                                               break;
-                                       case inBeginEnd:
-                                               stab.atom = currentAtom;
-                                               switch (type) {
-                                                       case N_ENSYM:
-                                                               state = start;
-                                                               currentAtom = NULL;
-                                                               break;
-                                                       case N_LCSYM:
-                                                       case N_STSYM:
-                                                       {
-                                                               BaseAtom* nestedAtom = (BaseAtom*)this->findAtomAndOffset(sym->n_value()).atom;
-                                                               if ( nestedAtom != NULL ) {
-                                                                       stab.atom = nestedAtom;
-                                                                       stab.string = symString;
-                                                               }
-                                                               else {
-                                                                       warning("can't find atom for stabs 0x%X at %08llX in %s",
-                                                                               type, (uint64_t)sym->n_value(), path);
-                                                               }
-                                                               break;
-                                                       }
-                                                       case N_LBRAC:
-                                                       case N_RBRAC:
-                                                       case N_SLINE:
-                                                               // adjust value to be offset in atom
-                                                               stab.value -= currentAtomAddress;
-                                                       default:
-                                                               stab.string = symString;
-                                                               break;
-                                               }
-                                               break;
-                                       case inFun:
-                                               switch (type) {
-                                                       case N_FUN:
-                                                               if ( sym->n_sect() != 0 ) {
-                                                                       // found another start stab, must be really old stabs...
-                                                                       currentAtomAddress = sym->n_value();
-                                                                       currentAtom = (BaseAtom*)this->findAtomAndOffset(currentAtomAddress).atom;
-                                                                       if ( currentAtom != NULL ) {
-                                                                               stab.atom = currentAtom;
-                                                                               stab.string = symString;
-                                                                       }
-                                                                       else {
-                                                                               warning("can't find atom for stabs FUN at %08llX in %s",
-                                                                                       (uint64_t)currentAtomAddress, path);
-                                                                       }
-                                                               }
-                                                               else {
-                                                                       // found ending stab, switch back to start state
-                                                                       stab.string = symString;
-                                                                       stab.atom = currentAtom;
-                                                                       state = start;
-                                                                       currentAtom = NULL;
-                                                               }
-                                                               break;
-                                                       case N_LBRAC:
-                                                       case N_RBRAC:
-                                                       case N_SLINE:
-                                                               // adjust value to be offset in atom
-                                                               stab.value -= currentAtomAddress;
-                                                               stab.atom = currentAtom;
-                                                               break;
-                                                       case N_SO:
-                                                               stab.string = symString;
-                                                               state = start;
-                                                               break;
-                                                       default:
-                                                               stab.atom = currentAtom;
-                                                               stab.string = symString;
-                                                               break;
-                                               }
-                                               break;
-                               }
-                               // add to list of stabs for this .o file
-                               if ( useStab )
-                                       fStabs.push_back(stab);
-                       }
-               }
-       }
-
-#if 0
-       // special case precompiled header .o file (which has no content) to have one empty atom
-       if ( fAtoms.size() == 0 ) {
-               int pathLen = strlen(path);
-               if ( (pathLen > 6) && (strcmp(&path[pathLen-6], ".gch.o")==0) ) {
-                       ObjectFile::Atom* phony = new AnonymousAtom<A>(*this, (uint32_t)0);
-                       //phony->fSynthesizedName = ".gch.o";
-                       fAtoms.push_back(phony);
-               }
-       }
-#endif
-
-       // sort all atoms by address
-       std::sort(fAtoms.begin(), fAtoms.end(), BaseAtomSorter());
-
-       // set ordinal and sort references in each atom
-       uint32_t index = fOrdinalBase;
-       for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) {
-               BaseAtom* atom = (BaseAtom*)(*it);
-               atom->setOrdinal(index++);
-               atom->sortReferences();
-       }
-       
-}
-
-template <typename A>
-const macho_section<typename A::P>* Reader<A>::getSectionForAddress(pint_t addr)
-{
-       for (const macho_section<P>* sect=fSectionsStart; sect < fSectionsEnd; ++sect) {
-               if ( (sect->addr() <= addr) && (addr < (sect->addr()+sect->size())) ) 
-                       return sect;
-       }
-       throwf("section not found for address 0x%08llX", (uint64_t)addr);
-}
-
-template <typename A>
-ObjectFile::Atom* Reader<A>::getFunctionAtomFromFDEAddress(pint_t addr)
-{
-       for (typename std::vector<FDE_Atom_Info>::const_iterator it = fFDEInfos.begin(); it != fFDEInfos.end(); ++it) {
-               if ( it->fdeAddress == addr ) {
-                       return findAtomAndOffset(it->function.address).atom;
-               }
-       }
-       // CIEs won't be in fFDEInfos
-       return NULL;
-}
-
-template <typename A>
-ObjectFile::Atom* Reader<A>::getFunctionAtomFromLSDAAddress(pint_t addr)
-{
-       for (typename std::vector<FDE_Atom_Info>::const_iterator it = fFDEInfos.begin(); it != fFDEInfos.end(); ++it) {
-               if ( it->lsda.address == addr ) {
-                       return findAtomAndOffset(it->function.address).atom;
-               }
-       }
-       return NULL;
-}
-
-
-template <>
-void ObjectFileAddressSpace<x86_64>::buildRelocatedMap(const macho_section<P>* sect, std::map<uint32_t,uint64_t>& map)
-{      
-       // mach-o x86_64 is different, the content of a section with a relocation is the addend
-       const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fReader.fHeader) + sect->reloff());
-       const macho_relocation_info<P>* relocsEnd = &relocs[sect->nreloc()];
-       for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
-               std::map<uint32_t,uint64_t>::iterator pos;
-               switch ( reloc->r_type() ) {
-                       case X86_64_RELOC_UNSIGNED:
-                               pos = map.find(reloc->r_address());
-                               if ( pos != map.end() )
-                                       pos->second += fReader.fSymbols[reloc->r_symbolnum()].n_value();
-                               else
-                                       map[reloc->r_address()] = fReader.fSymbols[reloc->r_symbolnum()].n_value();
-                               break;
-                       case X86_64_RELOC_SUBTRACTOR:
-                               map[reloc->r_address()] = -fReader.fSymbols[reloc->r_symbolnum()].n_value();
-                               break;
-                       case X86_64_RELOC_GOT:
-                               // there is no good address to return here.
-                               // GOT slots are synthsized by the linker
-                               // this is used for the reference to the personality function in CIEs
-                               map[reloc->r_address()] = 0;
-                               break;
-                       default:
-                               fprintf(stderr, "ObjectFileAddressSpace::buildRelocatedMap() unexpected relocation at r_address=0x%08X\n", reloc->r_address());
-                               break;
-               }
-       }
-}
-
-template <typename A>
-void ObjectFileAddressSpace<A>::buildRelocatedMap(const macho_section<P>* sect, std::map<uint32_t,uint64_t>& map)
-{
-       // in all architectures except x86_64, the section contents are already fixed up to point
-       // to content in the same object file.
-}
-
-template <>
-uint64_t ObjectFileAddressSpace<x86_64>::relocated(uint32_t sectOffset, uint32_t relocsOffset, uint32_t relocsCount)
-{      
-       // mach-o x86_64 is different, the content of a section with a relocation is the addend
-       uint64_t result = 0;
-       const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fReader.fHeader) + relocsOffset);
-       const macho_relocation_info<P>* relocsEnd = &relocs[relocsCount];
-       for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
-               //fprintf(stderr, "ObjectFileAddressSpace::relocated(0x%08X), r_address=0x%08X\n", sectOffset, reloc->r_address());
-               if ( reloc->r_address() == sectOffset ) {
-                       switch ( reloc->r_type() ) {
-                               case X86_64_RELOC_UNSIGNED:
-                                       result += fReader.fSymbols[reloc->r_symbolnum()].n_value();
-                                       break;
-                               case X86_64_RELOC_SUBTRACTOR:
-                                       result -= fReader.fSymbols[reloc->r_symbolnum()].n_value();
-                                       break;
-                               case X86_64_RELOC_GOT:
-                                       // there is no good address to return here.
-                                       // GOT slots are synthsized by the linker
-                                       // this is used for the reference to the personality function in CIEs
-                                       result = 0;
-                                       break;
-                               default:
-                                       fprintf(stderr, "ObjectFileAddressSpace::relocated(0x%08X) => type=%d, value=0x%08X\n", sectOffset, reloc->r_type(), reloc->r_symbolnum());
-                                       break;
-                       }
-               }
-       }
-       //fprintf(stderr, "ObjectFileAddressSpace::relocated(0x%08X) => 0x%0llX\n", sectOffset, result);
-       return result;
-}
-
-template <typename A>
-typename A::P::uint_t ObjectFileAddressSpace<A>::relocated(uint32_t sectOffset, uint32_t relocsOffset, uint32_t relocsCount)
-{
-       // in all architectures except x86_64, the section contents are already fixed up to point
-       // to content in the same object file.
-       return 0;
-}
-
-
-
-// FSF exception handling Pointer-Encoding constants 
-// Used in CFI augmentation by gcc compiler
-enum {
-       DW_EH_PE_ptr       = 0x00,
-       DW_EH_PE_uleb128   = 0x01,
-       DW_EH_PE_udata2    = 0x02,
-       DW_EH_PE_udata4    = 0x03,
-       DW_EH_PE_udata8    = 0x04,
-       DW_EH_PE_signed    = 0x08,
-       DW_EH_PE_sleb128   = 0x09,
-       DW_EH_PE_sdata2    = 0x0A,
-       DW_EH_PE_sdata4    = 0x0B,
-       DW_EH_PE_sdata8    = 0x0C,
-       DW_EH_PE_absptr    = 0x00,
-       DW_EH_PE_pcrel     = 0x10,
-       DW_EH_PE_textrel   = 0x20,
-       DW_EH_PE_datarel   = 0x30,
-       DW_EH_PE_funcrel   = 0x40,
-       DW_EH_PE_aligned   = 0x50,
-       DW_EH_PE_indirect  = 0x80,
-       DW_EH_PE_omit      = 0xFF
-};
-
-template <>
-void Reader<x86_64>::addCiePersonalityReference(BaseAtom* cieAtom, uint32_t offsetInCIE, uint8_t encoding)
-{
-       if ( encoding != (DW_EH_PE_indirect|DW_EH_PE_pcrel|DW_EH_PE_sdata4) )
-               throw "unexpected personality encoding in CIE";
-
-       // walk relocs looking for reloc in this CIE
-       uint32_t sectOffset = (cieAtom->getObjectAddress() + offsetInCIE) - fehFrameSection->addr();
-       const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fHeader) + fehFrameSection->reloff());
-       const macho_relocation_info<P>* relocsEnd = &relocs[fehFrameSection->nreloc()];
-       for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
-               if ( reloc->r_address() == sectOffset ) {
-                       switch ( reloc->r_type() ) {
-                               case X86_64_RELOC_GOT:
-                                       if ( !reloc->r_extern() )
-                                               throw "GOT reloc not extern for personality function";
-                                       new Reference<x86_64>(x86_64::kPCRel32GOT, AtomAndOffset(cieAtom, offsetInCIE), &fStrings[fSymbols[reloc->r_symbolnum()].n_strx()], 4);
-                                       return;
-                               default:
-                                       throw "expected GOT reloc for personality function";
-                       }
-               }
-       }
-       throw "personality function not found for CIE";
-}
-
-template <>
-bool Reader<ppc>::isSectDiffReloc(uint8_t r_type)
-{
-       switch ( r_type ) {
-               case PPC_RELOC_LOCAL_SECTDIFF:
-               case PPC_RELOC_SECTDIFF:
-                       return true;
-       }
-       return false;
-}
-
-template <>
-bool Reader<ppc64>::isSectDiffReloc(uint8_t r_type)
-{
-       switch ( r_type ) {
-               case PPC_RELOC_LOCAL_SECTDIFF:
-               case PPC_RELOC_SECTDIFF:
-                       return true;
-       }
-       return false;
-}
-
-template <>
-bool Reader<x86>::isSectDiffReloc(uint8_t r_type)
-{
-       switch ( r_type ) {
-               case GENERIC_RELOC_LOCAL_SECTDIFF:
-               case GENERIC_RELOC_SECTDIFF:
-                       return true;
-       }
-       return false;
-}
-
-template <>
-bool Reader<arm>::isSectDiffReloc(uint8_t r_type)
-{
-       switch ( r_type ) {
-               case ARM_RELOC_LOCAL_SECTDIFF:
-               case ARM_RELOC_SECTDIFF:
-                       return true;
-       }
-       return false;
-}
-
-template <typename A>
-void Reader<A>::addCiePersonalityReference(BaseAtom* cieAtom, uint32_t offsetInCIE, uint8_t encoding)
-{
-       if ( (encoding != (DW_EH_PE_indirect|DW_EH_PE_pcrel|DW_EH_PE_sdata4)) && (encoding != (DW_EH_PE_indirect|DW_EH_PE_pcrel)) )
-               throw "unexpected personality encoding in CIE";
-
-       // walk relocs looking for personality reloc in this CIE
-       uint32_t sectOffset = (cieAtom->getObjectAddress() + offsetInCIE) - fehFrameSection->addr();
-       const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fHeader) + fehFrameSection->reloff());
-       const macho_relocation_info<P>* relocsEnd = &relocs[fehFrameSection->nreloc()];
-       for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
-               if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
-                       // ignore
-               }
-               else {
-               const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
-                       if ( sreloc->r_address() == sectOffset ) {
-                               if ( isSectDiffReloc(sreloc->r_type()) ) {
-                                       // r_value is address of non-lazy-pointer to personality function
-                                       new Reference<A>(A::kPointerDiff32, AtomAndOffset(cieAtom, offsetInCIE), AtomAndOffset(cieAtom, offsetInCIE), 
-                                                                                       findAtomAndOffset(sreloc->r_value()));
-                                       return;
-                               }
-                       }
-               }
-       }
-       throw "can't find relocation for personality in CIE";
-}
-
-template <typename A>
-void Reader<A>::addFdeReference(uint8_t encoding, AtomAndOffset inFDE, AtomAndOffset target)
-{
-       if ( (encoding & 0xF0) != DW_EH_PE_pcrel ) 
-               throw "unsupported encoding in FDE";
-       Kinds kind = A::kNoFixUp;
-       switch ( encoding & 0xF ) {
-               case DW_EH_PE_ptr:
-                       kind = A::kPointerDiff;
-                       break;
-               case DW_EH_PE_sdata4:
-                       kind = A::kPointerDiff32;
-                       break;
-               default:
-                       throw "unsupported encoding in FDE";
-       }
-       new Reference<A>(kind, inFDE, inFDE, target);
-}
-
-template <typename A>
-typename A::P::uint_t ObjectFileAddressSpace<A>::getEncodedP(pint_t& addr, pint_t end, uint8_t encoding)
-{
-       pint_t startAddr = addr;
-       pint_t p = addr;
-       pint_t result;
-       
-       // first get value
-       switch (encoding & 0x0F) {
-               case DW_EH_PE_ptr:
-                       result = getP(addr);
-                       p += sizeof(pint_t);
-                       addr = (pint_t)p;
-                       break;
-               case DW_EH_PE_uleb128:
-                       result = getULEB128(addr, end);
-                       break;
-               case DW_EH_PE_udata2:
-                       result = get16(addr);
-                       p += 2;
-                       addr = (pint_t)p;
-                       break;
-               case DW_EH_PE_udata4:
-                       result = get32(addr);
-                       p += 4;
-                       addr = (pint_t)p;
-                       break;
-               case DW_EH_PE_udata8:
-                       result = get64(addr);
-                       p += 8;
-                       addr = (pint_t)p;
-                       break;
-               case DW_EH_PE_sleb128:
-                       result = getSLEB128(addr, end);
-                       break;
-               case DW_EH_PE_sdata2:
-                       result = (int16_t)get16(addr);
-                       p += 2;
-                       addr = (pint_t)p;
-                       break;
-               case DW_EH_PE_sdata4:
-                       result = (int32_t)get32(addr);
-                       p += 4;
-                       addr = (pint_t)p;
-                       break;
-               case DW_EH_PE_sdata8:
-                       result = get64(addr);
-                       p += 8;
-                       addr = (pint_t)p;
-                       break;
-               default:
-                       throwf("ObjectFileAddressSpace<A>::getEncodedP() encoding 0x%08X not supported", encoding);
-       }
-       
-       // then add relative offset
-       switch ( encoding & 0x70 ) {
-               case DW_EH_PE_absptr:
-                       // do nothing
-                       break;
-               case DW_EH_PE_pcrel:
-                       // <rdar://problem/7200658> pc-rel sdata4 should return zero if content is zero
-                       if ( (result != 0) || ((encoding & DW_EH_PE_indirect) != 0) )
-                               result += startAddr;
-                       break;
-               case DW_EH_PE_textrel:
-                       throw "DW_EH_PE_textrel pointer encoding not supported";
-                       break;
-               case DW_EH_PE_datarel:
-                       throw "DW_EH_PE_datarel pointer encoding not supported";
-                       break;
-               case DW_EH_PE_funcrel:
-                       throw "DW_EH_PE_funcrel pointer encoding not supported";
-                       break;
-               case DW_EH_PE_aligned:
-                       throw "DW_EH_PE_aligned pointer encoding not supported";
-                       break;
-               default:
-                       throwf("ObjectFileAddressSpace<A>::getEncodedP() encoding 0x%08X not supported", encoding);
-                       break;
-       }
-       
-       if ( encoding & DW_EH_PE_indirect )
-               result = getP(result);
-       
-       return result;
-}
-
-template <>
-uint32_t SymbolAtom<x86>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
-{
-       pint_t lsda;
-       pint_t personality;
-       char warningBuffer[1024];
-       uint32_t result = libunwind::DwarfInstructions<class ObjectFileAddressSpace<x86>, libunwind::Registers_x86>::createCompactEncodingFromFDE(
-                                                                                       fOwner.fObjectAddressSpace, ehAtomAddress, &lsda, &personality, warningBuffer);
-       if ( (result & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF ) {
-               //if ( fOwner.fOptions.fForDyld )
-               //      throwf("can't make compact unwind encoding from dwarf for %s",  this->getDisplayName());
-               //else
-                       if ( fOwner.fOptions.fWarnCompactUnwind )
-                               warning("can't make compact unwind encoding from dwarf for %s in %s because %s", this->getDisplayName(), fOwner.getPath(), warningBuffer);
-       }
-       return result;
-}
-
-template <>
-uint32_t SymbolAtom<x86_64>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
-{
-       pint_t lsda;
-       pint_t personality;
-       char warningBuffer[1024];
-       uint32_t result = libunwind::DwarfInstructions<class ObjectFileAddressSpace<x86_64>, libunwind::Registers_x86_64>::createCompactEncodingFromFDE(
-                                                                                       fOwner.fObjectAddressSpace, ehAtomAddress, &lsda, &personality, warningBuffer);
-       if ( (result & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF ) {
-               //if ( fOwner.fOptions.fForDyld )
-               //      throwf("can't make compact unwind encoding from dwarf for %s",  this->getDisplayName());
-               //else
-                       if ( fOwner.fOptions.fWarnCompactUnwind )
-                               warning("can't make compact unwind encoding from dwarf for %s in %s because %s", this->getDisplayName(), fOwner.getPath(), warningBuffer);
-       }
-       return result;
-}
-
-template <>
-uint32_t SymbolAtom<ppc>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
-{
-       // compact encoding not supported for ppc
-       return 0;
-}
-
-template <>
-uint32_t SymbolAtom<ppc64>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
-{
-       // compact encoding not supported for ppc64
-       return 0;
-}
-
-template <>
-uint32_t SymbolAtom<arm>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
-{
-       // compact encoding not supported for arm
-       return 0;
-}
-
-
-template <typename A>
-uint8_t SymbolAtom<A>::getLSDAReferenceKind() const 
-{
-       return A::kGroupSubordinate;
-}
-
-template <>
-uint8_t SymbolAtom<x86_64>::getPersonalityReferenceKind() const
-{
-       return x86_64::kGOTNoFixUp;
-}
-
-template <>
-uint8_t SymbolAtom<x86>::getPersonalityReferenceKind() const
-{
-       return x86::kNoFixUp;
-}
-
-template <typename A>
-uint8_t SymbolAtom<A>::getPersonalityReferenceKind() const
-{
-       // only used with architectures that support compact unwinding 
-       return 0;
-}
-
-
-template <>
-uint32_t AnonymousAtom<x86>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
-{
-       pint_t lsda;
-       pint_t personality;
-       char warningBuffer[1024];
-       uint32_t result = libunwind::DwarfInstructions<class ObjectFileAddressSpace<x86>, libunwind::Registers_x86>::createCompactEncodingFromFDE(
-                                                                                       fOwner.fObjectAddressSpace, ehAtomAddress, &lsda, &personality, warningBuffer);
-       if ( (result & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF ) {
-               //if ( fOwner.fOptions.fForDyld )
-               //      throwf("can't make compact unwind encoding from dwarf for %s",  this->getDisplayName());
-               //else
-               if ( fOwner.fOptions.fWarnCompactUnwind )
-                       warning("can't make compact unwind encoding from dwarf for %s in %s", this->getDisplayName(), fOwner.getPath());
-       }
-       return result;
-}
-
-template <>
-uint32_t AnonymousAtom<x86_64>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
-{
-       pint_t lsda;
-       pint_t personality;
-       char warningBuffer[1024];
-       uint32_t result = libunwind::DwarfInstructions<class ObjectFileAddressSpace<x86_64>, libunwind::Registers_x86_64>::createCompactEncodingFromFDE(
-                                                                                               fOwner.fObjectAddressSpace, ehAtomAddress, &lsda, &personality, warningBuffer);
-       if ( (result & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF ) {
-               //if ( fOwner.fOptions.fForDyld )
-               //      throwf("can't make compact unwind encoding from dwarf for %s",  this->getDisplayName());
-               //else
-               if ( fOwner.fOptions.fWarnCompactUnwind )
-                       warning("can't make compact unwind encoding from dwarf for %s in %s", this->getDisplayName(), fOwner.getPath());
-       }
-       return result;
-}
-
-template <>
-uint32_t AnonymousAtom<ppc>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
-{
-       // compact encoding not supported for ppc
-       return 0;
-}
-
-template <>
-uint32_t AnonymousAtom<ppc64>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
-{
-       // compact encoding not supported for ppc64
-       return 0;
-}
-
-template <>
-uint32_t AnonymousAtom<arm>::getCompactUnwindEncoding(uint64_t ehAtomAddress)
-{
-       // compact encoding not supported for arm
-       return 0;
-}
-
-
-template <typename A>
-uint8_t AnonymousAtom<A>::getLSDAReferenceKind() const 
-{
-       return A::kGroupSubordinate;
-}
-
-template <>
-uint8_t AnonymousAtom<x86_64>::getPersonalityReferenceKind() const
-{
-       return x86_64::kGOTNoFixUp;
-}
-
-template <>
-uint8_t AnonymousAtom<x86>::getPersonalityReferenceKind() const
-{
-       return x86::kNoFixUp;
-}
-
-template <typename A>
-uint8_t AnonymousAtom<A>::getPersonalityReferenceKind() const
-{
-       // only used with architectures that support compact unwinding 
-       return 0;
-}
-
-
-
-
-
-
-
-template <>
-void Reader<ppc>::setCpuConstraint(uint32_t cpusubtype)
-{
-       switch (cpusubtype) {
-               case CPU_SUBTYPE_POWERPC_ALL:
-               case CPU_SUBTYPE_POWERPC_750:
-               case CPU_SUBTYPE_POWERPC_7400:
-               case CPU_SUBTYPE_POWERPC_7450:
-               case CPU_SUBTYPE_POWERPC_970:
-                       fCpuConstraint = cpusubtype;
-                       break;
-               default:
-                       warning("unknown ppc subtype 0x%08X in %s, defaulting to ALL", cpusubtype, fPath);
-                       fCpuConstraint = CPU_SUBTYPE_POWERPC_ALL;
-            break;
-       }
-}
-
-template <>
-void Reader<arm>::setCpuConstraint(uint32_t cpusubtype)
-{
-       switch (cpusubtype) {
-               case CPU_SUBTYPE_ARM_ALL:
-               case CPU_SUBTYPE_ARM_V4T:
-               case CPU_SUBTYPE_ARM_V5TEJ:
-               case CPU_SUBTYPE_ARM_V6:
-               case CPU_SUBTYPE_ARM_XSCALE:
-               case CPU_SUBTYPE_ARM_V7:
-                       fCpuConstraint = cpusubtype;
-                       break;
-               default:
-                       warning("unknown arm subtype 0x%08X in %s, defaulting to ALL", cpusubtype, fPath);
-                       fCpuConstraint = CPU_SUBTYPE_ARM_ALL;
-            break;
-       }
-}
-
-template <typename A>
-void Reader<A>::setCpuConstraint(uint32_t cpusubtype)
-{
-       // no cpu sub types for this architecture
-}
-
-template <>
-uint32_t Reader<ppc>::updateCpuConstraint(uint32_t previous)
-{
-       switch ( previous ) {
-    case CPU_SUBTYPE_POWERPC_ALL:
-        return fCpuConstraint;
-        break;
-    case CPU_SUBTYPE_POWERPC_750:
-        if ( fCpuConstraint == CPU_SUBTYPE_POWERPC_7400 ||
-             fCpuConstraint == CPU_SUBTYPE_POWERPC_7450 ||
-             fCpuConstraint == CPU_SUBTYPE_POWERPC_970 )
-            return fCpuConstraint;
-        break;
-    case CPU_SUBTYPE_POWERPC_7400:
-    case CPU_SUBTYPE_POWERPC_7450:
-        if ( fCpuConstraint == CPU_SUBTYPE_POWERPC_970 )
-            return fCpuConstraint;
-        break;
-    case CPU_SUBTYPE_POWERPC_970:
-        // G5 can run everything
-        break;
-    default:
-        throw "Unhandled PPC cpu subtype!";
-        break;
-       }
-    return previous;
-}
-
-
-
-template <>
-uint32_t Reader<arm>::updateCpuConstraint(uint32_t previous)
-{
-    switch (previous) {
-               case CPU_SUBTYPE_ARM_ALL:
-                       return fCpuConstraint;
-                       break;
-               case CPU_SUBTYPE_ARM_V5TEJ:
-                       // v6, v7, and xscale are more constrained than previous file (v5), so use it
-                       if (   (fCpuConstraint == CPU_SUBTYPE_ARM_V6)
-                               || (fCpuConstraint == CPU_SUBTYPE_ARM_V7) 
-                               || (fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE) )
-                               return fCpuConstraint;
-                       break;
-               case CPU_SUBTYPE_ARM_V4T:
-                       // v5, v6, v7, and xscale are more constrained than previous file (v4t), so use it
-                       if (   (fCpuConstraint == CPU_SUBTYPE_ARM_V7)
-                               || (fCpuConstraint == CPU_SUBTYPE_ARM_V6)
-                               || (fCpuConstraint == CPU_SUBTYPE_ARM_V5TEJ)
-                               || (fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE) )
-                               return fCpuConstraint;
-                       break;
-               case CPU_SUBTYPE_ARM_V6:
-                       // v6 can run everything except xscale and v7
-                       if ( fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE )
-                               throw "can't mix xscale and v6 code";
-                       if ( fCpuConstraint == CPU_SUBTYPE_ARM_V7 )
-                               return fCpuConstraint;
-                       break;
-               case CPU_SUBTYPE_ARM_XSCALE:
-                       // xscale can run everything except v6 and v7
-                       if ( fCpuConstraint == CPU_SUBTYPE_ARM_V6 )
-                               throw "can't mix xscale and v6 code";
-                       if ( fCpuConstraint == CPU_SUBTYPE_ARM_V7 )
-                               throw "can't mix xscale and v7 code";
-                       break;
-               case CPU_SUBTYPE_ARM_V7:
-                       // v7 can run everything except xscale
-                       if ( fCpuConstraint == CPU_SUBTYPE_ARM_XSCALE )
-                               throw "can't mix xscale and v7 code";
-                       break;
-               default:
-                       throw "Unhandled ARM cpu subtype!";
-    }
-    return previous;
-}
-
-template <typename A>
-uint32_t Reader<A>::updateCpuConstraint(uint32_t current)
-{
-       // no cpu sub types for this architecture
-       return current;
-}
-
-template <typename A>
-void Reader<A>::addDtraceExtraInfos(uint32_t probeAddr, const char* providerName)
-{
-       // for every ___dtrace_stability$* and ___dtrace_typedefs$* undefine with
-       // a matching provider name, add a by-name kDtraceTypeReference at probe site
-       const char* dollar = strchr(providerName, '$');
-       if ( dollar != NULL ) {
-               int providerNameLen = dollar-providerName+1;
-               for ( std::vector<const char*>::iterator it = fDtraceProviderInfo.begin(); it != fDtraceProviderInfo.end(); ++it) {
-                       const char* typeDollar = strchr(*it, '$');
-                       if ( typeDollar != NULL ) {
-                               if ( strncmp(typeDollar+1, providerName, providerNameLen) == 0 ) {
-                                       makeByNameReference(A::kDtraceTypeReference, probeAddr, *it, 0);
-                               }
-                       }
-               }
-       }
-}
-
-
-template <>
-void Reader<x86_64>::validSectionType(uint8_t type)
-{
-       switch ( type ) {
-               case S_SYMBOL_STUBS:
-                       throw "symbol_stub sections not valid in x86_64 object files";
-               case S_LAZY_SYMBOL_POINTERS:
-                       throw "lazy pointer sections not valid in x86_64 object files";
-               case S_NON_LAZY_SYMBOL_POINTERS:
-                       throw "non lazy pointer sections not valid in x86_64 object files";
-       }
-}
-
-template <typename A>
-void Reader<A>::validSectionType(uint8_t type)
-{
-}
-
-template <typename A>
-bool Reader<A>::getTranslationUnitSource(const char** dir, const char** name) const
-{
-       if ( fDebugInfo == kDebugInfoDwarf ) {
-               *dir = fDwarfTranslationUnitDir;
-               *name = fDwarfTranslationUnitFile;
-               return (fDwarfTranslationUnitFile != NULL);
-       }
-       return false;
-}
-
-template <typename A>
-BaseAtom* Reader<A>::findAtomByName(const char* name)
-{
-       // first search the more important atoms
-       for (typename AddrToAtomMap::iterator it=fAddrToAtom.begin(); it != fAddrToAtom.end(); it++) {
-               const char* atomName = it->second->getName();
-               if ( (atomName != NULL) && (strcmp(atomName, name) == 0) ) {
-                       return it->second;
-               }
-       }
-       // try all atoms, because this might have been a tentative definition
-       for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) {
-               BaseAtom* atom = (BaseAtom*)(*it);
-               const char* atomName = atom->getName();
-               if ( (atomName != NULL) && (strcmp(atomName, name) == 0) ) {
-                       return atom;
-               }
-       }
-       return NULL;
-}
-
-template <typename A>
-Reference<A>* Reader<A>::makeReference(Kinds kind, pint_t atAddr, pint_t toAddr)
-{
-       return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(toAddr));
-}
-
-template <typename A>
-Reference<A>* Reader<A>::makeReference(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr)
-{
-       return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(fromAddr), findAtomAndOffset(toAddr));
-}
-
-template <typename A>
-Reference<A>* Reader<A>::makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t toAddr, pint_t toBaseAddr)
-{
-       return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(toBaseAddr, toAddr));
-}
-
-template <typename A>
-Reference<A>* Reader<A>::makeReferenceWithToBase(Kinds kind, pint_t atAddr, pint_t fromAddr, pint_t toAddr, pint_t toBaseAddr)
-{
-       return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(fromAddr), findAtomAndOffset(toBaseAddr, toAddr));
-}
-
-template <typename A>
-Reference<A>* Reader<A>::makeByNameReference(Kinds kind, pint_t atAddr, const char* toName, uint32_t toOffset)
-{
-       return new Reference<A>(kind, findAtomAndOffset(atAddr), toName, toOffset);
-}
-
-template <typename A>
-BaseAtom* Reader<A>::makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section<P>* ehSect)
-{
-       // add a group subordinate reference from function atom to its eh frame atom
-       const uint8_t* ehContent = (const uint8_t*)(fHeader) + ehAtomAddress - ehSect->addr() + ehSect->offset();
-       int32_t deltaMinus8 = P::getP(*(pint_t*)(&ehContent[8]));       // offset 8 in eh info is delta to function
-       pint_t funcAddr = ehAtomAddress + deltaMinus8 + 8;
-       ObjectFile::Atom* funcAtom = findAtomAndOffset(funcAddr).atom;
-       ObjectFile::Atom* ehAtom = findAtomAndOffset(ehAtomAddress).atom;
-       new Reference<A>(A::kGroupSubordinate, funcAtom, ehAtom);
-       return (BaseAtom*)funcAtom;
-}
-
-
-template <>
-Reference<x86_64>* Reader<x86_64>::makeByNameReference(Kinds kind, pint_t atAddr, const char* toName, uint32_t toOffset)
-{
-       // x86_64 uses external relocations everywhere, so external relocations do not imply by-name references
-       // instead check scope of target
-       BaseAtom* target = findAtomByName(toName);
-       if ( (target != NULL) && (target->getScope() == ObjectFile::Atom::scopeTranslationUnit) )
-               return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), AtomAndOffset(target, toOffset));
-       else
-               return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), toName, toOffset);
-}
-
-template <>
-Reference<x86_64>* Reader<x86_64>::makeReferenceToSymbol(Kinds kind, pint_t atAddr, const macho_nlist<P>* toSymbol, pint_t toOffset)
-{
-       // x86_64 uses external relocations everywhere, so external relocations do not imply by-name references
-       // instead check scope of target
-       const char* symbolName = &fStrings[toSymbol->n_strx()];
-       if ( ((toSymbol->n_type() & N_TYPE) == N_SECT) && (((toSymbol->n_type() & N_EXT) == 0) || (symbolName[0] == 'L')) ) {
-               AtomAndOffset targetAO = findAtomAndOffsetForSection(toSymbol->n_value(), toSymbol->n_sect());
-               targetAO.offset = toOffset;
-               return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), targetAO);
-       }
-       else
-               return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), symbolName, toOffset);
-}
-
-
-template <>
-BaseAtom* Reader<x86_64>::makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section<P>* ehSect)
-{
-       // add a group subordinate reference from function atom to its eh frame atom
-       // for x86_64 the __eh_frame section contains the addends, so need to use relocs to find target
-       uint32_t ehAtomDeltaSectionOffset = ehAtomAddress + 8 - ehSect->addr(); // offset 8 in eh info is delta to function
-       const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fHeader) + ehSect->reloff());
-       const macho_relocation_info<P>* relocsEnd = &relocs[ehSect->nreloc()];
-       for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
-               if ( (reloc->r_address() == ehAtomDeltaSectionOffset) && (reloc->r_type() == X86_64_RELOC_UNSIGNED) ) {
-                       pint_t funcAddr = fSymbols[reloc->r_symbolnum()].n_value();
-                       ObjectFile::Atom* funcAtom = findAtomAndOffset(funcAddr).atom;
-                       ObjectFile::Atom* ehAtom = findAtomAndOffset(ehAtomAddress).atom;
-                       new Reference<x86_64>(x86_64::kGroupSubordinate, funcAtom, ehAtom);
-                       return (BaseAtom*)funcAtom;
-               }
-       }
-       warning("can't find matching function for eh symbol %s", ehName);
-       return NULL;
-}
-
-template <typename A>
-AtomAndOffset Reader<A>::findAtomAndOffsetForSection(pint_t addr, unsigned int expectedSectionIndex)
-{
-       AtomAndOffset ao = findAtomAndOffset(addr);
-       if ( ao.atom != NULL ) {
-               if ( ((BaseAtom*)(ao.atom))->getSectionIndex() == expectedSectionIndex )
-                       return ao;
-       }
-       // The atom found is not in the section expected.
-       // This probably means there was a label at the end of the section.
-       // Do a slow sequential lookup
-       for (std::vector<BaseAtom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); ++it) {
-               BaseAtom* atom = *it;
-               if ( atom->getSectionIndex() == expectedSectionIndex ) {
-                       pint_t objAddr = atom->getObjectAddress();
-                       if ( (objAddr == addr) || ((objAddr < addr) && (objAddr+atom->getSize() > addr)) ) {
-                               return AtomAndOffset(atom, addr-atom->getObjectAddress());
-                       }
-               }
-       }
-       // no atom found that matched section, fall back to one orginally found
-       return ao;
-}
-
-template <typename A>
-AtomAndOffset Reader<A>::findAtomAndOffset(pint_t addr)
-{
-       // STL has no built-in for "find largest key that is same or less than"
-       typename AddrToAtomMap::iterator it = fAddrToAtom.upper_bound(addr);
-       // if no atoms up to this address return none found
-       if ( it == fAddrToAtom.begin() ) 
-               return AtomAndOffset(NULL);
-       // otherwise upper_bound gets us next key, so we back up one    
-       --it;
-       AtomAndOffset result;
-       result.atom = it->second;
-       result.offset = addr - it->first;
-       //fprintf(stderr, "findAtomAndOffset(0x%0llX) ==> %s (0x%0llX -> 0x%0llX)\n",
-       //                      (uint64_t)addr, result.atom->getDisplayName(), (uint64_t)it->first, it->first+result.atom->getSize());
-       return result;
-}
-
-// "scattered" relocations enable you to offset into an atom past the end of it
-// baseAddr is the address of the target atom,
-// realAddr is the points into it
-template <typename A>
-AtomAndOffset Reader<A>::findAtomAndOffset(pint_t baseAddr, pint_t realAddr)
-{
-       typename AddrToAtomMap::iterator it = fAddrToAtom.find(baseAddr);
-       if ( it != fAddrToAtom.end() ) {
-               AtomAndOffset result;
-               result.atom = it->second;
-               result.offset = realAddr - it->first;
-               if ( result.atom->isThumb() )
-                       result.offset &= -2;
-               //fprintf(stderr, "findAtomAndOffset(0x%08X, 0x%08X) => %s + 0x%08X\n", baseAddr, realAddr, result.atom->getDisplayName(), result.offset);
-               return result;
-       }
-       // getting here means we have a scattered relocation to an address without a label
-       // so, find the atom that contains the baseAddr, and offset from that to the readAddr
-       AtomAndOffset result = findAtomAndOffset(baseAddr);
-       result.offset += (realAddr-baseAddr);
-       return result;
-}
-
-
-/* Skip over a LEB128 value (signed or unsigned).  */
-static void
-skip_leb128 (const uint8_t ** offset, const uint8_t * end)
-{
-  while (*offset != end && **offset >= 0x80)
-    (*offset)++;
-  if (*offset != end)
-    (*offset)++;
-}
-
-/* Read a ULEB128 into a 64-bit word.  Return (uint64_t)-1 on overflow
-   or error.  On overflow, skip past the rest of the uleb128.  */
-static uint64_t
-read_uleb128 (const uint8_t ** offset, const uint8_t * end)
-{
-  uint64_t result = 0;
-  int bit = 0;
-
-  do  {
-    uint64_t b;
-
-    if (*offset == end)
-      return (uint64_t) -1;
-
-    b = **offset & 0x7f;
-
-    if (bit >= 64 || b << bit >> bit != b)
-      result = (uint64_t) -1;
-    else
-      result |= b << bit, bit += 7;
-  } while (*(*offset)++ >= 0x80);
-  return result;
-}
-
-
-/* Skip over a DWARF attribute of form FORM.  */
-template <typename A>
-bool Reader<A>::skip_form(const uint8_t ** offset, const uint8_t * end, uint64_t form,
-                                                       uint8_t addr_size, bool dwarf64)
-{
-  int64_t sz=0;
-
-  switch (form)
-    {
-    case DW_FORM_addr:
-      sz = addr_size;
-      break;
-
-    case DW_FORM_block2:
-      if (end - *offset < 2)
-       return false;
-      sz = 2 + A::P::E::get16(*(uint16_t*)offset);
-      break;
-
-    case DW_FORM_block4:
-      if (end - *offset < 4)
-       return false;
-      sz = 2 + A::P::E::get32(*(uint32_t*)offset);
-      break;
-
-    case DW_FORM_data2:
-    case DW_FORM_ref2:
-      sz = 2;
-      break;
-
-    case DW_FORM_data4:
-    case DW_FORM_ref4:
-      sz = 4;
-      break;
-
-    case DW_FORM_data8:
-    case DW_FORM_ref8:
-      sz = 8;
-      break;
-
-    case DW_FORM_string:
-      while (*offset != end && **offset)
-       ++*offset;
-    case DW_FORM_data1:
-    case DW_FORM_flag:
-    case DW_FORM_ref1:
-      sz = 1;
-      break;
-
-    case DW_FORM_block:
-      sz = read_uleb128 (offset, end);
-      break;
-
-    case DW_FORM_block1:
-      if (*offset == end)
-       return false;
-      sz = 1 + **offset;
-      break;
-
-    case DW_FORM_sdata:
-    case DW_FORM_udata:
-    case DW_FORM_ref_udata:
-      skip_leb128 (offset, end);
-      return true;
-
-    case DW_FORM_strp:
-    case DW_FORM_ref_addr:
-      sz = 4;
-      break;
-
-    default:
-      return false;
-    }
-  if (end - *offset < sz)
-    return false;
-  *offset += sz;
-  return true;
-}
-
-template <typename A>
-const char* Reader<A>::getDwarfString(uint64_t form, const uint8_t* p)
-{
-       if ( form == DW_FORM_string )
-               return (const char*)p;
-       else if ( form == DW_FORM_strp ) {
-               uint32_t offset = E::get32(*((uint32_t*)p));
-               const char* dwarfStrings = (char*)(fHeader) + fDwarfDebugStringSect->offset();
-               if ( offset > fDwarfDebugStringSect->size() ) {
-                       warning("unknown dwarf DW_FORM_strp (offset=0x%08X) is too big in %s\n", offset, this->getPath());
-                       return NULL;
-               }
-               return &dwarfStrings[offset];
-       }
-       warning("unknown dwarf string encoding (form=%lld) in %s\n", form, this->getPath());
-       return NULL;
-}
-
-
-// Look at the compilation unit DIE and determine
-// its NAME, compilation directory (in COMP_DIR) and its
-// line number information offset (in STMT_LIST).  NAME and COMP_DIR
-// may be NULL (especially COMP_DIR) if they are not in the .o file;
-// STMT_LIST will be (uint64_t) -1.
-//
-// At present this assumes that there's only one compilation unit DIE.
-//
-template <typename A>
-bool Reader<A>::read_comp_unit(const char ** name, const char ** comp_dir,
-                                                       uint64_t *stmt_list)
-{
-       const uint8_t * debug_info;
-       const uint8_t * debug_abbrev;
-       const uint8_t * di;
-       const uint8_t * da;
-       const uint8_t * end;
-       const uint8_t * enda;
-       uint64_t sz;
-       uint16_t vers;
-       uint64_t abbrev_base;
-       uint64_t abbrev;
-       uint8_t address_size;
-       bool dwarf64;
-
-       *name = NULL;
-       *comp_dir = NULL;
-       *stmt_list = (uint64_t) -1;
-
-       if ( (fDwarfDebugInfoSect == NULL) || (fDwarfDebugAbbrevSect == NULL) )
-               return false;
-
-       debug_info = (uint8_t*)(fHeader) + fDwarfDebugInfoSect->offset();
-       debug_abbrev = (uint8_t*)(fHeader) + fDwarfDebugAbbrevSect->offset();
-       di = debug_info;
-
-       if (fDwarfDebugInfoSect->size() < 12)
-               /* Too small to be a real debug_info section.  */
-               return false;
-       sz = A::P::E::get32(*(uint32_t*)di);
-       di += 4;
-       dwarf64 = sz == 0xffffffff;
-       if (dwarf64)
-               sz = A::P::E::get64(*(uint64_t*)di), di += 8;
-       else if (sz > 0xffffff00)
-               /* Unknown dwarf format.  */
-               return false;
-
-       /* Verify claimed size.  */
-       if (sz + (di - debug_info) > fDwarfDebugInfoSect->size() || sz <= (dwarf64 ? 23 : 11))
-               return false;
-
-       vers = A::P::E::get16(*(uint16_t*)di);
-       if (vers < 2 || vers > 3)
-       /* DWARF version wrong for this code.
-          Chances are we could continue anyway, but we don't know for sure.  */
-               return false;
-       di += 2;
-
-       /* Find the debug_abbrev section.  */
-       abbrev_base = dwarf64 ? A::P::E::get64(*(uint64_t*)di) : A::P::E::get32(*(uint32_t*)di);
-       di += dwarf64 ? 8 : 4;
-
-       if (abbrev_base > fDwarfDebugAbbrevSect->size())
-               return false;
-       da = debug_abbrev + abbrev_base;
-       enda = debug_abbrev + fDwarfDebugAbbrevSect->size();
-
-       address_size = *di++;
-
-       /* Find the abbrev number we're looking for.  */
-       end = di + sz;
-       abbrev = read_uleb128 (&di, end);
-       if (abbrev == (uint64_t) -1)
-               return false;
-
-       /* Skip through the debug_abbrev section looking for that abbrev.  */
-       for (;;)
-       {
-               uint64_t this_abbrev = read_uleb128 (&da, enda);
-               uint64_t attr;
-
-               if (this_abbrev == abbrev)
-                       /* This is almost always taken.  */
-                       break;
-               skip_leb128 (&da, enda); /* Skip the tag.  */
-               if (da == enda)
-                       return false;
-               da++;  /* Skip the DW_CHILDREN_* value.  */
-
-               do {
-                       attr = read_uleb128 (&da, enda);
-                       skip_leb128 (&da, enda);
-               } while (attr != 0 && attr != (uint64_t) -1);
-               if (attr != 0)
-                       return false;
-       }
-
-       /* Check that the abbrev is one for a DW_TAG_compile_unit.  */
-       if (read_uleb128 (&da, enda) != DW_TAG_compile_unit)
-       return false;
-       if (da == enda)
-       return false;
-       da++;  /* Skip the DW_CHILDREN_* value.  */
-
-       /* Now, go through the DIE looking for DW_AT_name,
-        DW_AT_comp_dir, and DW_AT_stmt_list.  */
-       for (;;)
-       {
-               uint64_t attr = read_uleb128 (&da, enda);
-               uint64_t form = read_uleb128 (&da, enda);
-
-               if (attr == (uint64_t) -1)
-                       return false;
-               else if (attr == 0)
-                       return true;
-
-               if (form == DW_FORM_indirect)
-                       form = read_uleb128 (&di, end);
-
-               if (attr == DW_AT_name)
-                       *name = getDwarfString(form, di);
-               else if (attr == DW_AT_comp_dir)
-                       *comp_dir = getDwarfString(form, di);
-               else if (attr == DW_AT_stmt_list && form == DW_FORM_data4)
-                       *stmt_list = A::P::E::get32(*(uint32_t*)di);
-               else if (attr == DW_AT_stmt_list && form == DW_FORM_data8)
-                       *stmt_list = A::P::E::get64(*(uint64_t*)di);
-               if (! skip_form (&di, end, form, address_size, dwarf64))
-                       return false;
-       }
-}
-
-template <typename A>
-const char* Reader<A>::assureFullPath(const char* path)
-{
-       if ( path[0] == '/' )
-               return path;
-       char cwdbuff[MAXPATHLEN];
-       if ( getcwd(cwdbuff, MAXPATHLEN) != NULL ) {
-               char* result;
-               asprintf(&result, "%s/%s", cwdbuff, path);
-               if ( result != NULL )
-                       return result;
-       }
-       return path;
-}
-
-
-//
-//
-//     To implement architecture xxx, you must write template specializations for the following six methods:
-//                     Reader<xxx>::validFile()
-//                     Reader<xxx>::addRelocReference()
-//                     Reference<xxx>::getDescription()
-//
-//
-
-
-template <>
-bool Reader<ppc>::validFile(const uint8_t* fileContent, bool, cpu_subtype_t)
-{
-       const macho_header<P>* header = (const macho_header<P>*)fileContent;
-       if ( header->magic() != MH_MAGIC )
-               return false;
-       if ( header->cputype() != CPU_TYPE_POWERPC )
-               return false;
-       if ( header->filetype() != MH_OBJECT )
-               return false;
-       return true;
-}
-
-template <>
-bool Reader<ppc64>::validFile(const uint8_t* fileContent, bool, cpu_subtype_t)
-{
-       const macho_header<P>* header = (const macho_header<P>*)fileContent;
-       if ( header->magic() != MH_MAGIC_64 )
-               return false;
-       if ( header->cputype() != CPU_TYPE_POWERPC64 )
-               return false;
-       if ( header->filetype() != MH_OBJECT )
-               return false;
-       return true;
-}
-
-template <>
-bool Reader<x86>::validFile(const uint8_t* fileContent, bool, cpu_subtype_t)
-{
-       const macho_header<P>* header = (const macho_header<P>*)fileContent;
-       if ( header->magic() != MH_MAGIC )
-               return false;
-       if ( header->cputype() != CPU_TYPE_I386 )
-               return false;
-       if ( header->filetype() != MH_OBJECT )
-               return false;
-       return true;
-}
-
-template <>
-bool Reader<x86_64>::validFile(const uint8_t* fileContent, bool, cpu_subtype_t)
-{
-       const macho_header<P>* header = (const macho_header<P>*)fileContent;
-       if ( header->magic() != MH_MAGIC_64 )
-               return false;
-       if ( header->cputype() != CPU_TYPE_X86_64 )
-               return false;
-       if ( header->filetype() != MH_OBJECT )
-               return false;
-       return true;
-}
-
-template <>
-bool Reader<arm>::validFile(const uint8_t* fileContent, bool subtypeMustMatch, cpu_subtype_t subtype)
-{
-       const macho_header<P>* header = (const macho_header<P>*)fileContent;
-       if ( header->magic() != MH_MAGIC )
-               return false;
-       if ( header->cputype() != CPU_TYPE_ARM )
-               return false;
-       if ( header->filetype() != MH_OBJECT )
-               return false;
-       if ( subtypeMustMatch && ((cpu_subtype_t)header->cpusubtype() != subtype) )
-               return false;
-       return true;
-}
-
-
-template <>
-const char* Reader<ppc>::fileKind(const uint8_t* fileContent)
-{
-       const macho_header<P>* header = (const macho_header<P>*)fileContent;
-       if ( header->magic() != MH_MAGIC )
-               return NULL;
-       if ( header->cputype() != CPU_TYPE_POWERPC )
-               return NULL;
-       switch ( header->cpusubtype() ) {
-               case CPU_SUBTYPE_POWERPC_750:
-                       return "ppc750";
-               case CPU_SUBTYPE_POWERPC_7400:
-                       return "ppc7400";
-               case CPU_SUBTYPE_POWERPC_7450:
-                       return "ppc7450";
-               case CPU_SUBTYPE_POWERPC_970:
-                       return "ppc970";
-               case CPU_SUBTYPE_POWERPC_ALL:
-                       return "ppc";
-       }
-       return "ppc???";
-}
-
-template <>
-const char* Reader<ppc64>::fileKind(const uint8_t* fileContent)
-{
-       const macho_header<P>* header = (const macho_header<P>*)fileContent;
-       if ( header->magic() != MH_MAGIC )
-               return NULL;
-       if ( header->cputype() != CPU_TYPE_POWERPC64 )
-               return NULL;
-       return "ppc64";
-}
-
-template <>
-const char* Reader<x86>::fileKind(const uint8_t* fileContent)
-{
-       const macho_header<P>* header = (const macho_header<P>*)fileContent;
-       if ( header->magic() != MH_MAGIC )
-               return NULL;
-       if ( header->cputype() != CPU_TYPE_I386 )
-               return NULL;
-       return "i386";
-}
-
-template <>
-const char* Reader<x86_64>::fileKind(const uint8_t* fileContent)
-{
-       const macho_header<P>* header = (const macho_header<P>*)fileContent;
-       if ( header->magic() != MH_MAGIC )
-               return NULL;
-       if ( header->cputype() != CPU_TYPE_X86_64 )
-               return NULL;
-       return "x86_64";
-}
-
-template <>
-const char* Reader<arm>::fileKind(const uint8_t* fileContent)
-{
-       const macho_header<P>* header = (const macho_header<P>*)fileContent;
-       if ( header->magic() != MH_MAGIC )
-               return NULL;
-       if ( header->cputype() != CPU_TYPE_ARM )
-               return NULL;
-       switch ( header->cpusubtype() ) {
-               case CPU_SUBTYPE_ARM_V4T:
-                       return "armv4t";
-               case CPU_SUBTYPE_ARM_V5TEJ:
-                       return "armv5";
-               case CPU_SUBTYPE_ARM_V6:
-                       return "armv6";
-               case CPU_SUBTYPE_ARM_V7:
-                       return "armv7";
-       }
-       return "arm???";
-}
-
-
-template <typename A>
-bool Reader<A>::isWeakImportSymbol(const macho_nlist<P>* sym)
-{
-       return ( ((sym->n_type() & N_TYPE) == N_UNDF) && ((sym->n_desc() & N_WEAK_REF) != 0) );
-}
-
-template <>
-bool Reader<ppc64>::addRelocReference(const macho_section<ppc64::P>* sect, const macho_relocation_info<ppc64::P>* reloc)
-{
-       return addRelocReference_powerpc(sect, reloc);
-}
-
-template <>
-bool Reader<ppc>::addRelocReference(const macho_section<ppc::P>* sect, const macho_relocation_info<ppc::P>* reloc)
-{
-       return addRelocReference_powerpc(sect, reloc);
-}
-
-
-//
-// ppc and ppc64 both use the same relocations, so process them in one common routine
-//
-template <typename A>
-bool Reader<A>::addRelocReference_powerpc(const macho_section<typename A::P>* sect,
-                                                                                 const macho_relocation_info<typename A::P>* reloc)
-{
-       uint32_t srcAddr;
-       uint32_t dstAddr;
-       uint32_t* fixUpPtr;
-       int32_t displacement = 0;
-       uint32_t instruction = 0;
-       uint32_t offsetInTarget;
-       int16_t lowBits;
-       bool result = false;
-       if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
-               const macho_relocation_info<P>* nextReloc = &reloc[1];
-               const char* targetName = NULL;
-               bool weakImport = false;
-               fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
-               if ( reloc->r_type() != PPC_RELOC_PAIR )
-                       instruction = BigEndian::get32(*fixUpPtr);
-               srcAddr = sect->addr() + reloc->r_address();
-               if ( reloc->r_extern() ) {
-                       const macho_nlist<P>* targetSymbol = &fSymbols[reloc->r_symbolnum()];
-                       targetName = &fStrings[targetSymbol->n_strx()];
-                       weakImport = this->isWeakImportSymbol(targetSymbol);
-               }
-               switch ( reloc->r_type() ) {
-                       case PPC_RELOC_BR24:
-                               {
-                                       if ( (instruction & 0x4C000000) == 0x48000000 ) {
-                                               displacement = (instruction & 0x03FFFFFC);
-                                               if ( (displacement & 0x02000000) != 0 )
-                                                       displacement |= 0xFC000000;
-                                       }
-                                       else {
-                                               printf("bad instruction for BR24 reloc");
-                                       }
-                                       if ( reloc->r_extern() ) {
-                                               offsetInTarget = srcAddr + displacement;
-                                               if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
-                                                       makeByNameReference(A::kDtraceProbeSite, srcAddr, targetName, 0);
-                                                       addDtraceExtraInfos(srcAddr, &targetName[16]);
-                                               }
-                                               else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
-                                                       makeByNameReference(A::kDtraceIsEnabledSite, srcAddr, targetName, 0);
-                                                       addDtraceExtraInfos(srcAddr, &targetName[20]);
-                                               }
-                                               else if ( weakImport )
-                                                       makeByNameReference(A::kBranch24WeakImport, srcAddr, targetName, offsetInTarget);
-                                               else
-                                                       makeByNameReference(A::kBranch24, srcAddr, targetName, offsetInTarget);
-                                       }
-                                       else {
-                                               dstAddr = srcAddr + displacement;
-                                               // if this is a branch to a stub, we need to see if the stub is for a weak imported symbol
-                                               ObjectFile::Atom* atom = findAtomAndOffset(dstAddr).atom;
-                                               targetName = atom->getName();
-                                               if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) {
-                                                       makeByNameReference(A::kDtraceProbeSite, srcAddr, targetName, 0);
-                                                       addDtraceExtraInfos(srcAddr, &targetName[16]);
-                                               }
-                                               else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) {
-                                                       makeByNameReference(A::kDtraceIsEnabledSite, srcAddr, targetName, 0);
-                                                       addDtraceExtraInfos(srcAddr, &targetName[20]);
-                                               }
-                                               else if ( (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
-                                                       && ((AnonymousAtom<A>*)atom)->isWeakImportStub() )
-                                                       makeReference(A::kBranch24WeakImport, srcAddr, dstAddr);
-                                               else
-                                                       makeReference(A::kBranch24, srcAddr, dstAddr);
-                                       }
-                               }
-                               break;
-                       case PPC_RELOC_BR14:
-                               {
-                                       displacement = (instruction & 0x0000FFFC);
-                                       if ( (displacement & 0x00008000) != 0 )
-                                               displacement |= 0xFFFF0000;
-                                       if ( reloc->r_extern() ) {
-                                               offsetInTarget = srcAddr + displacement;
-                                               makeByNameReference(A::kBranch14, srcAddr, targetName, offsetInTarget);
-                                       }
-                                       else {
-                                               dstAddr = srcAddr + displacement;
-                                               makeReference(A::kBranch14, srcAddr, dstAddr);
-                                       }
-                               }
-                               break;
-                       case PPC_RELOC_PAIR:
-                               // skip, processed by a previous look ahead
-                               break;
-                       case PPC_RELOC_LO16:
-                               {
-                                       if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
-                                               throw "PPC_RELOC_LO16 missing following pair";
-                                       }
-                                       result = true;
-                                       lowBits = (instruction & 0xFFFF);
-                                       if ( reloc->r_extern() ) {
-                                               offsetInTarget = (nextReloc->r_address() << 16) | ((uint32_t)lowBits & 0x0000FFFF);
-                                               makeByNameReference(A::kAbsLow16, srcAddr, targetName, offsetInTarget);
-                                       }
-                                       else {
-                                               dstAddr = (nextReloc->r_address() << 16) + ((uint32_t)lowBits & 0x0000FFFF);
-                                               if ( reloc->r_symbolnum() == R_ABS ) {
-                                                       // find absolute symbol that corresponds to pointerValue
-                                                       typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
-                                                       if ( pos != fAddrToAbsoluteAtom.end() ) 
-                                                               makeByNameReference(A::kAbsLow16, srcAddr, pos->second->getName(), 0);
-                                                       else
-                                                               makeReference(A::kAbsLow16, srcAddr, dstAddr);
-                                               }
-                                               else {
-                                                       makeReference(A::kAbsLow16, srcAddr, dstAddr);
-                                               }
-                                       }
-                               }
-                               break;
-                       case PPC_RELOC_LO14:
-                               {
-                                       if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
-                                               throw "PPC_RELOC_LO14 missing following pair";
-                                       }
-                                       result = true;
-                                       lowBits = (instruction & 0xFFFC);
-                                       if ( reloc->r_extern() ) {
-                                               offsetInTarget = (nextReloc->r_address() << 16) | ((uint32_t)lowBits & 0x0000FFFF);
-                                               makeByNameReference(A::kAbsLow14, srcAddr, targetName, offsetInTarget);
-                                       }
-                                       else {
-                                               dstAddr = (nextReloc->r_address() << 16) | ((uint32_t)lowBits & 0x0000FFFF);
-                                               if ( reloc->r_symbolnum() == R_ABS ) {
-                                                       // find absolute symbol that corresponds to pointerValue
-                                                       typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
-                                                       if ( pos != fAddrToAbsoluteAtom.end() ) 
-                                                               makeByNameReference(A::kAbsLow14, srcAddr, pos->second->getName(), 0);
-                                                       else
-                                                               makeReference(A::kAbsLow14, srcAddr, dstAddr);
-                                               }
-                                               else {
-                                                       makeReference(A::kAbsLow14, srcAddr, dstAddr);
-                                               }
-                                       }
-                               }
-                               break;
-                       case PPC_RELOC_HI16:
-                               {
-                                       if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
-                                               throw "PPC_RELOC_HI16 missing following pair";
-                                       }
-                                       result = true;
-                                       if ( reloc->r_extern() ) {
-                                               offsetInTarget = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF);
-                                               makeByNameReference(A::kAbsHigh16, srcAddr, targetName, offsetInTarget);
-                                       }
-                                       else {
-                                               dstAddr = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF);
-                                               if ( reloc->r_symbolnum() == R_ABS ) {
-                                                       // find absolute symbol that corresponds to pointerValue
-                                                       typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
-                                                       if ( pos != fAddrToAbsoluteAtom.end() ) 
-                                                               makeByNameReference(A::kAbsHigh16, srcAddr, pos->second->getName(), 0);
-                                                       else
-                                                               makeReference(A::kAbsHigh16, srcAddr, dstAddr);
-                                               }
-                                               else {
-                                                       makeReference(A::kAbsHigh16, srcAddr, dstAddr);
-                                               }
-                                       }
-                               }
-                               break;
-                       case PPC_RELOC_HA16:
-                               {
-                                       if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
-                                               throw "PPC_RELOC_HA16 missing following pair";
-                                       }
-                                       result = true;
-                                       lowBits = (nextReloc->r_address() & 0x0000FFFF);
-                                       if ( reloc->r_extern() ) {
-                                               offsetInTarget = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
-                                               makeByNameReference(A::kAbsHigh16AddLow, srcAddr, targetName, offsetInTarget);
-                                       }
-                                       else {
-                                               dstAddr = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
-                                               if ( reloc->r_symbolnum() == R_ABS ) {
-                                                       // find absolute symbol that corresponds to pointerValue
-                                                       typename AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
-                                                       if ( pos != fAddrToAbsoluteAtom.end() ) 
-                                                               makeByNameReference(A::kAbsHigh16AddLow, srcAddr, pos->second->getName(), 0);
-                                                       else
-                                                               makeReference(A::kAbsHigh16AddLow, srcAddr, dstAddr);
-                                               }
-                                               else {
-                                                       makeReference(A::kAbsHigh16AddLow, srcAddr, dstAddr);
-                                               }
-                                       }
-                               }
-                               break;
-                       case PPC_RELOC_VANILLA:
-                               {
-                                       pint_t pointerValue = P::getP(*((pint_t*)fixUpPtr));
-                                       if ( reloc->r_extern() ) {
-                                               if ( weakImport )
-                                                       makeByNameReference(A::kPointerWeakImport, srcAddr, targetName, pointerValue);
-                                               else
-                                                       makeByNameReference(A::kPointer, srcAddr, targetName, pointerValue);
-                                       }
-                                       else {
-                                               new Reference<A>(A::kPointer, findAtomAndOffset(srcAddr), findAtomAndOffsetForSection(pointerValue, reloc->r_symbolnum()));
-                                       }
-                               }
-                               break;
-                       case PPC_RELOC_JBSR:
-                               // this is from -mlong-branch codegen.  We ignore the jump island and make reference to the real target
-                               if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
-                                       throw "PPC_RELOC_JBSR missing following pair";
-                               }
-                               if ( !fHasLongBranchStubs )
-                                       warning("object file compiled with -mlong-branch which is no longer needed. To remove this warning, recompile without -mlong-branch: %s", fPath);
-                               fHasLongBranchStubs = true;
-                               result = true;
-                               if ( reloc->r_extern() ) {
-                                       throw "PPC_RELOC_JBSR should not be using an external relocation";
-                               }
-                               makeReference(A::kBranch24, srcAddr, nextReloc->r_address());
-                               if ( (instruction & 0x4C000000) == 0x48000000 ) {
-                                       displacement = (instruction & 0x03FFFFFC);
-                                       if ( (displacement & 0x02000000) != 0 )
-                                               displacement |= 0xFC000000;
-                               }
-                               else {
-                                       fprintf(stderr, "bad instruction for BR24 reloc");
-                               }
-                               break;
-                       default:
-                               warning("unknown relocation type %d", reloc->r_type());
-               }
-       }
-       else {
-               const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
-               srcAddr = sect->addr() + sreloc->r_address();
-               dstAddr = sreloc->r_value();
-               uint32_t betterDstAddr;
-               fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address());
-               const macho_scattered_relocation_info<P>* nextSReloc = &sreloc[1];
-               const macho_relocation_info<P>* nextReloc = &reloc[1];
-               // file format allows pair to be scattered or not
-               bool nextRelocIsPair = false;
-               uint32_t nextRelocAddress = 0;
-               uint32_t nextRelocValue = 0;
-               if ( (nextReloc->r_address() & R_SCATTERED) == 0 ) {
-                       if ( nextReloc->r_type() == PPC_RELOC_PAIR ) {
-                               nextRelocIsPair = true;
-                               nextRelocAddress = nextReloc->r_address();
-                               result = true;
-                       }
-               }
-               else {
-                       if ( nextSReloc->r_type() == PPC_RELOC_PAIR ) {
-                               nextRelocIsPair = true;
-                               nextRelocAddress = nextSReloc->r_address();
-                               nextRelocValue = nextSReloc->r_value();
-                               result = true;
-                       }
-               }
-               switch (sreloc->r_type()) {
-                       case PPC_RELOC_VANILLA:
-                               {
-                                       betterDstAddr = P::getP(*(pint_t*)fixUpPtr);
-                                       //fprintf(stderr, "scattered pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08X\n", srcAddr, dstAddr, betterDstAddr);
-                                       // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
-                                       makeReferenceWithToBase(A::kPointer, srcAddr, betterDstAddr, dstAddr);
-                               }
-                               break;
-                       case PPC_RELOC_BR14:
-                               {
-                                       instruction = BigEndian::get32(*fixUpPtr);
-                                       displacement = (instruction & 0x0000FFFC);
-                                       if ( (displacement & 0x00008000) != 0 )
-                                               displacement |= 0xFFFF0000;
-                                       betterDstAddr = srcAddr+displacement;
-                                       //fprintf(stderr, "betterDstAddr=0x%08X, srcAddr=0x%08X, displacement=0x%08X\n",  betterDstAddr, srcAddr, displacement);
-                                       makeReferenceWithToBase(A::kBranch14, srcAddr, betterDstAddr, dstAddr);
-                               }
-                               break;
-                       case PPC_RELOC_BR24:
-                               {
-                                       instruction = BigEndian::get32(*fixUpPtr);
-                                       if ( (instruction & 0x4C000000) == 0x48000000 ) {
-                                               displacement = (instruction & 0x03FFFFFC);
-                                               if ( (displacement & 0x02000000) != 0 )
-                                                       displacement |= 0xFC000000;
-                                               betterDstAddr = srcAddr+displacement;
-                                               makeReferenceWithToBase(A::kBranch24, srcAddr, betterDstAddr, dstAddr);
-                                       }
-                               }
-                               break;
-                       case PPC_RELOC_LO16_SECTDIFF:
-                               {
-                                       if ( ! nextRelocIsPair ) {
-                                               throw "PPC_RELOC_LO16_SECTDIFF missing following pair";
-                                       }
-                                       instruction = BigEndian::get32(*fixUpPtr);
-                                       lowBits = (instruction & 0xFFFF);
-                                       displacement = (nextRelocAddress << 16) | ((uint32_t)lowBits & 0x0000FFFF);
-                                       makeReferenceWithToBase(A::kPICBaseLow16, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr);
-                               }
-                               break;
-                       case PPC_RELOC_LO14_SECTDIFF:
-                               {
-                                       if ( ! nextRelocIsPair ) {
-                                               throw "PPC_RELOC_LO14_SECTDIFF missing following pair";
-                                       }
-                                       instruction = BigEndian::get32(*fixUpPtr);
-                                       lowBits = (instruction & 0xFFFC);
-                                       displacement = (nextRelocAddress << 16) | ((uint32_t)lowBits & 0x0000FFFF);
-                                       makeReferenceWithToBase(A::kPICBaseLow14, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr);
-                               }
-                               break;
-                       case PPC_RELOC_HA16_SECTDIFF:
-                               {
-                                       if ( ! nextRelocIsPair ) {
-                                               throw "PPC_RELOC_HA16_SECTDIFF missing following pair";
-                                       }
-                                       instruction = BigEndian::get32(*fixUpPtr);
-                                       lowBits = (nextRelocAddress & 0x0000FFFF);
-                                       displacement = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
-                                       makeReferenceWithToBase(A::kPICBaseHigh16, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr);
-                               }
-                               break;
-                       case PPC_RELOC_LO14:
-                               {
-                                       if ( ! nextRelocIsPair ) {
-                                               throw "PPC_RELOC_LO14 missing following pair";
-                                       }
-                                       instruction = BigEndian::get32(*fixUpPtr);
-                                       lowBits = (instruction & 0xFFFC);
-                                       betterDstAddr = (nextRelocAddress << 16) + ((uint32_t)lowBits & 0x0000FFFF);
-                                       makeReferenceWithToBase(A::kAbsLow14, srcAddr, betterDstAddr, dstAddr);
-                               }
-                               break;
-                       case PPC_RELOC_LO16:
-                               {
-                                       if ( ! nextRelocIsPair ) {
-                                               throw "PPC_RELOC_LO16 missing following pair";
-                                       }
-                                       instruction = BigEndian::get32(*fixUpPtr);
-                                       lowBits = (instruction & 0xFFFF);
-                                       betterDstAddr = (nextRelocAddress << 16) + ((uint32_t)lowBits & 0x0000FFFF);
-                                       makeReferenceWithToBase(A::kAbsLow16, srcAddr, betterDstAddr, dstAddr);
-                               }
-                               break;
-                       case PPC_RELOC_HA16:
-                               {
-                                       if ( ! nextRelocIsPair ) {
-                                               throw "PPC_RELOC_HA16 missing following pair";
-                                       }
-                                       instruction = BigEndian::get32(*fixUpPtr);
-                                       lowBits = (nextRelocAddress & 0xFFFF);
-                                       betterDstAddr = ((instruction & 0xFFFF) << 16) + (int32_t)lowBits;
-                                       makeReferenceWithToBase(A::kAbsHigh16AddLow, srcAddr, betterDstAddr, dstAddr);
-                               }
-                               break;
-                       case PPC_RELOC_HI16:
-                               {
-                                       if ( ! nextRelocIsPair ) {
-                                               throw "PPC_RELOC_HI16 missing following pair";
-                                       }
-                                       instruction = BigEndian::get32(*fixUpPtr);
-                                       lowBits = (nextRelocAddress & 0xFFFF);
-                                       betterDstAddr = ((instruction & 0xFFFF) << 16) | (lowBits & 0x0000FFFF);
-                                       makeReferenceWithToBase(A::kAbsHigh16, srcAddr, betterDstAddr, dstAddr);
-                               }
-                               break;
-                       case PPC_RELOC_SECTDIFF:
-                       case PPC_RELOC_LOCAL_SECTDIFF:
-                               {
-                                       if ( ! nextRelocIsPair ) {
-                                               throw "PPC_RELOC_SECTDIFF missing following pair";
-                                       }
-                                       Kinds kind = A::kPointerDiff32;;
-                                       uint32_t contentAddr = 0;
-                                       switch ( sreloc->r_length() ) {
-                                               case 0:
-                                                       throw "bad diff relocations r_length (0) for ppc architecture";
-                                               case 1:
-                                                       kind = A::kPointerDiff16;
-                                                       contentAddr = BigEndian::get16(*((uint16_t*)fixUpPtr));
-                                                       break;
-                                               case 2:
-                                                       kind = A::kPointerDiff32;
-                                                       contentAddr = BigEndian::get32(*fixUpPtr);
-                                                       break;
-                                               case 3:
-                                                       kind = A::kPointerDiff64;
-                                                       contentAddr = BigEndian::get64(*((uint64_t*)fixUpPtr));
-                                                       break;
-                                       }
-                                       AtomAndOffset srcao  = findAtomAndOffset(srcAddr);
-                                       AtomAndOffset fromao = findAtomAndOffset(nextRelocValue);
-                                       AtomAndOffset toao   = findAtomAndOffset(dstAddr);
-                                       // check for addend encoded in the section content
-                                       //fprintf(stderr, "addRef: dstAddr=0x%X, nextRelocValue=0x%X, contentAddr=0x%X\n",
-                                       //              dstAddr, nextRelocValue, contentAddr);
-                                       if ( (dstAddr - nextRelocValue) != contentAddr ) {
-                                               if ( toao.atom == srcao.atom )
-                                                       toao.offset += (contentAddr + nextRelocValue) - dstAddr;
-                                               else if ( fromao.atom == srcao.atom )
-                                                       toao.offset += (contentAddr + nextRelocValue) - dstAddr;
-                                               else
-                                                       fromao.offset += (dstAddr - contentAddr) - nextRelocValue;
-                                       }
-                                       //fprintf(stderr, "addRef: src=%s+0x%X, from=%s+0x%X, to=%s+0x%X\n",
-                                       //      srcao.atom->getDisplayName(), srcao.offset, 
-                                       //      fromao.atom->getDisplayName(), fromao.offset, 
-                                       //      toao.atom->getDisplayName(), toao.offset);
-                                       new Reference<A>(kind, srcao, fromao, toao);
-                               }
-                               break;
-                       case PPC_RELOC_PAIR:
-                               break;
-                       case PPC_RELOC_HI16_SECTDIFF:
-                               warning("unexpected scattered relocation type PPC_RELOC_HI16_SECTDIFF");
-                               break;
-                       default:
-                               warning("unknown scattered relocation type %d", sreloc->r_type());
-               }
-       }
-       return result;
-}
-
-
-template <>
-bool Reader<x86>::addRelocReference(const macho_section<x86::P>* sect, const macho_relocation_info<x86::P>* reloc)
-{
-       uint32_t srcAddr;
-       uint32_t dstAddr;
-       uint32_t* fixUpPtr;
-       bool result = false;
-       if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
-               srcAddr = sect->addr() + reloc->r_address();
-               fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
-               switch ( reloc->r_type() ) {
-                       case GENERIC_RELOC_VANILLA:
-                               {
-                                       x86::ReferenceKinds kind = x86::kPointer;
-                                       uint32_t pointerValue = E::get32(*fixUpPtr);
-                                       if ( reloc->r_pcrel() ) {
-                                               switch( reloc->r_length() ) {
-                                                       case 0:
-                                                               kind = x86::kPCRel8;
-                                                               pointerValue = srcAddr + *((int8_t*)fixUpPtr) + sizeof(int8_t);
-                                                               break;
-                                                       case 1:
-                                                               kind = x86::kPCRel16;
-                                                               pointerValue = srcAddr + (int16_t)E::get16(*((uint16_t*)fixUpPtr)) + sizeof(uint16_t);
-                                                               break;
-                                                       case 2:
-                                                               kind = x86::kPCRel32;
-                                                               pointerValue += srcAddr + sizeof(uint32_t);
-                                                               break;
-                                                       case 3:
-                                                               throw "bad pc-rel vanilla relocation length";
-                                               }
-                                       }
-                                       else if ( strcmp(sect->segname(), "__TEXT") == 0 ) {
-                                               kind = x86::kAbsolute32;
-                                               if ( reloc->r_length() != 2 )
-                                                       throw "bad vanilla relocation length";
-                                       }
-                                       else {
-                                               kind = x86::kPointer;
-                                               if ( reloc->r_length() != 2 )
-                                                       throw "bad vanilla relocation length";
-                                       }
-                                       if ( reloc->r_extern() ) {
-                                               const macho_nlist<P>* targetSymbol = &fSymbols[reloc->r_symbolnum()];
-                                               if ( this->isWeakImportSymbol(targetSymbol) ) {
-                                                       if ( reloc->r_pcrel() )
-                                                               kind = x86::kPCRel32WeakImport;
-                                                       else
-                                                               kind = x86::kPointerWeakImport;
-                                               }
-                                               const char* targetName = &fStrings[targetSymbol->n_strx()];
-                                               if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
-                                                       makeByNameReference(x86::kDtraceProbeSite, srcAddr, targetName, 0);
-                                                       addDtraceExtraInfos(srcAddr, &targetName[16]);
-                                               }
-                                               else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
-                                                       makeByNameReference(x86::kDtraceIsEnabledSite, srcAddr, targetName, 0);
-                                                       addDtraceExtraInfos(srcAddr, &targetName[20]);
-                                               }
-                                               else
-                                                       makeByNameReference(kind, srcAddr, targetName, pointerValue);
-                                       }
-                                       else {
-                                               AtomAndOffset targetAO = findAtomAndOffsetForSection(pointerValue, reloc->r_symbolnum());
-                                               const char* targetName = targetAO.atom->getName();
-                                               if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) {
-                                                       makeByNameReference(x86::kDtraceProbeSite, srcAddr, targetName, 0);
-                                                       addDtraceExtraInfos(srcAddr, &targetName[16]);
-                                               }
-                                               else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) {
-                                                       makeByNameReference(x86::kDtraceIsEnabledSite, srcAddr, targetName, 0);
-                                                       addDtraceExtraInfos(srcAddr, &targetName[20]);
-                                               }
-                                               // if this is a reference to a stub, we need to see if the stub is for a weak imported symbol
-                                               else if ( reloc->r_pcrel() && (targetAO.atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
-                                                       && ((AnonymousAtom<x86>*)targetAO.atom)->isWeakImportStub() )
-                                                       new Reference<x86>(x86::kPCRel32WeakImport, findAtomAndOffset(srcAddr), targetAO);
-                                               else if ( reloc->r_symbolnum() != R_ABS )
-                                                       new Reference<x86>(kind, findAtomAndOffset(srcAddr), targetAO);
-                                               else {
-                                                       // find absolute symbol that corresponds to pointerValue
-                                                       AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(pointerValue);
-                                                       if ( pos != fAddrToAbsoluteAtom.end() ) 
-                                                               makeByNameReference(kind, srcAddr, pos->second->getName(), 0);
-                                                       else
-                                                               throwf("R_ABS reloc but no absolute symbol at target address");
-                                               }
-                                       }
-                               }
-                               break;
-                       default:
-                               warning("unknown relocation type %d", reloc->r_type());
-               }
-       }
-       else {
-               const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
-               srcAddr = sect->addr() + sreloc->r_address();
-               dstAddr = sreloc->r_value();
-               fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address());
-               const macho_scattered_relocation_info<P>* nextSReloc = &sreloc[1];
-               const macho_relocation_info<P>* nextReloc = &reloc[1];
-               pint_t betterDstAddr;
-               // file format allows pair to be scattered or not
-               bool nextRelocIsPair = false;
-               uint32_t nextRelocAddress = 0;
-               uint32_t nextRelocValue = 0;
-               if ( (nextReloc->r_address() & R_SCATTERED) == 0 ) {
-                       if ( nextReloc->r_type() == GENERIC_RELOC_PAIR ) {
-                               nextRelocIsPair = true;
-                               nextRelocAddress = nextReloc->r_address();
-                               result = true;
-                       }
-               }
-               else {
-                       if ( nextSReloc->r_type() == GENERIC_RELOC_PAIR ) {
-                               nextRelocIsPair = true;
-                               nextRelocAddress = nextSReloc->r_address();
-                               nextRelocValue = nextSReloc->r_value();
-                       }
-               }
-               switch (sreloc->r_type()) {
-                       case GENERIC_RELOC_VANILLA:
-                                       betterDstAddr = LittleEndian::get32(*fixUpPtr);
-                                       //fprintf(stderr, "pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08lX\n", srcAddr, dstAddr, betterDstAddr);
-                                       // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
-                                       if ( sreloc->r_pcrel() ) {
-                                               switch ( sreloc->r_length() ) {
-                                                       case 2:
-                                                               betterDstAddr += srcAddr + 4;
-                                                               makeReferenceWithToBase(x86::kPCRel32, srcAddr, betterDstAddr, dstAddr);
-                                                               break;
-                                                       case 1:
-                                                               betterDstAddr = LittleEndian::get16(*((uint16_t*)fixUpPtr)) + srcAddr + 2;
-                                                               makeReferenceWithToBase(x86::kPCRel16, srcAddr, betterDstAddr, dstAddr);
-                                                               break;
-                                                       case 0:
-                                                               betterDstAddr = *((uint8_t*)fixUpPtr) + srcAddr + 1;
-                                                               makeReferenceWithToBase(x86::kPCRel8, srcAddr, betterDstAddr, dstAddr);
-                                                               break;
-                                                       case 3:
-                                                               throwf("unsupported r_length=3 for scattered pc-rel vanilla reloc");
-                                                               break;
-                                               }
-                                       }
-                                       else {
-                                               if ( sreloc->r_length() != 2 )
-                                                       throwf("unsupported r_length=%d for scattered vanilla reloc", sreloc->r_length());
-                                               if ( strcmp(sect->segname(), "__TEXT") == 0 )
-                                                       makeReferenceWithToBase(x86::kAbsolute32, srcAddr, betterDstAddr, dstAddr);
-                                               else
-                                                       makeReferenceWithToBase(x86::kPointer, srcAddr, betterDstAddr, dstAddr);
-                                       }
-                               break;
-                       case GENERIC_RELOC_SECTDIFF:
-                       case GENERIC_RELOC_LOCAL_SECTDIFF:
-                               {
-                                       if ( !nextRelocIsPair ) {
-                                               throw "GENERIC_RELOC_SECTDIFF missing following pair";
-                                       }
-                                       x86::ReferenceKinds kind = x86::kPointerDiff;
-                                       uint32_t contentAddr = 0;
-                                       switch ( sreloc->r_length() ) {
-                                               case 0:
-                                               case 3:
-                                                       throw "bad length for GENERIC_RELOC_SECTDIFF";
-                                               case 1:
-                                                       kind = x86::kPointerDiff16;
-                                                       contentAddr = LittleEndian::get16(*((uint16_t*)fixUpPtr));
-                                                       break;
-                                               case 2:
-                                                       kind = x86::kPointerDiff;
-                                                       contentAddr = LittleEndian::get32(*fixUpPtr);
-                                                       break;
-                                       }
-                                       AtomAndOffset srcao  = findAtomAndOffset(srcAddr);
-                                       AtomAndOffset fromao = findAtomAndOffset(nextRelocValue);
-                                       AtomAndOffset toao   = findAtomAndOffset(dstAddr);
-                                       // check for addend encoded in the section content
-                                       //fprintf(stderr, "addRef: dstAddr=0x%X, nextRelocValue=0x%X, contentAddr=0x%X\n",
-                                       //              dstAddr, nextRelocValue, contentAddr);
-                                       if ( (dstAddr - nextRelocValue) != contentAddr ) {
-                                               if ( toao.atom == srcao.atom )
-                                                       toao.offset += (contentAddr + nextRelocValue) - dstAddr;
-                                               else if ( fromao.atom == srcao.atom )
-                                                       toao.offset += (contentAddr + nextRelocValue) - dstAddr;
-                                               else
-                                                       fromao.offset += (dstAddr - contentAddr) - nextRelocValue;
-                                       }
-                                       //fprintf(stderr, "addRef: src=%s+0x%X, from=%s+0x%X, to=%s+0x%X\n",
-                                       //      srcao.atom->getDisplayName(), srcao.offset, 
-                                       //      fromao.atom->getDisplayName(), fromao.offset, 
-                                       //      toao.atom->getDisplayName(), toao.offset);
-                                       new Reference<x86>(kind, srcao, fromao, toao);
-                               }
-                               break;
-                       case GENERIC_RELOC_PAIR:
-                               // do nothing, already used via a look ahead
-                               break;
-                       default:
-                               warning("unknown scattered relocation type %d", sreloc->r_type());
-               }
-       }
-       return result;
-}
-
-template <>
-bool Reader<x86_64>::addRelocReference(const macho_section<x86_64::P>* sect, const macho_relocation_info<x86_64::P>* reloc)
-{
-       uint64_t srcAddr;
-       uint64_t dstAddr = 0;
-       uint64_t addend;
-       uint32_t* fixUpPtr;
-       x86_64::ReferenceKinds kind = x86_64::kNoFixUp;
-       bool result = false;
-       const macho_nlist<P>* targetSymbol = NULL;
-       const char* targetName = NULL;
-       srcAddr = sect->addr() + reloc->r_address();
-       fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
-       //fprintf(stderr, "addReloc type=%d, len=%d, address=0x%X\n", reloc->r_type(), reloc->r_length(), reloc->r_address());
-       if ( reloc->r_extern() ) {
-               targetSymbol = &fSymbols[reloc->r_symbolnum()];
-               targetName = &fStrings[targetSymbol->n_strx()];
-       }
-       switch ( reloc->r_type() ) {
-               case X86_64_RELOC_UNSIGNED:
-                       if ( reloc->r_pcrel() )
-                               throw "pcrel and X86_64_RELOC_UNSIGNED not supported";
-                       switch ( reloc->r_length() ) {
-                               case 0:
-                               case 1:
-                                       throw "length < 2 and X86_64_RELOC_UNSIGNED not supported";
-                               case 2:
-                                       kind = x86_64::kPointer32;
-                                       break;
-                               case 3:
-                                       if ( reloc->r_extern() && isWeakImportSymbol(targetSymbol) )
-                                               kind = x86_64::kPointerWeakImport;
-                                       else
-                                               kind = x86_64::kPointer;
-                                       break;
-                       }
-                       dstAddr = E::get64(*((uint64_t*)fixUpPtr));
-                       if ( reloc->r_extern() ) {
-                               makeReferenceToSymbol(kind, srcAddr, targetSymbol, dstAddr);
-                       }
-                       else {
-                               makeReference(kind, srcAddr, dstAddr);
-                               // verify that dstAddr is in the section being targeted
-                               int sectNum = reloc->r_symbolnum();
-                               const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)fSegment + sizeof(macho_segment_command<P>));
-                               const macho_section<P>* const targetSection = &sectionsStart[sectNum-1];
-                               if ( (dstAddr < targetSection->addr()) || (dstAddr > (targetSection->addr()+targetSection->size())) ) {
-                                       throwf("local relocation for address 0x%08llX in section %s does not target section %s", 
-                                                       srcAddr, sect->sectname(), targetSection->sectname());
-                               }
-                       }
-                       break;
-               case X86_64_RELOC_SIGNED:
-               case X86_64_RELOC_SIGNED_1:
-               case X86_64_RELOC_SIGNED_2:
-               case X86_64_RELOC_SIGNED_4:
-                       if ( ! reloc->r_pcrel() )
-                               throw "not pcrel and X86_64_RELOC_SIGNED* not supported";
-                       if ( reloc->r_length() != 2 ) 
-                               throw "length != 2 and X86_64_RELOC_SIGNED* not supported";
-                       addend = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
-                       if ( reloc->r_extern() ) {
-                               switch ( reloc->r_type() ) {
-                                       case X86_64_RELOC_SIGNED:
-                                               kind = x86_64::kPCRel32;
-                                               // begin support for old .o files before X86_64_RELOC_SIGNED_1 was created
-                                               if ( addend == (uint64_t)(-1) ) {
-                                                       addend = 0;
-                                                       kind = x86_64::kPCRel32_1;
-                                               }
-                                               else if ( addend == (uint64_t)(-2) ) {
-                                                       addend = 0;
-                                                       kind = x86_64::kPCRel32_2;
-                                               }
-                                               else if ( addend == (uint64_t)(-4) ) {
-                                                       addend = 0;
-                                                       kind = x86_64::kPCRel32_4;
-                                               }
-                                               break;
-                                               // end support for old .o files before X86_64_RELOC_SIGNED_1 was created
-                                       case X86_64_RELOC_SIGNED_1:
-                                               kind = x86_64::kPCRel32_1;
-                                               addend += 1;
-                                               break;  
-                                       case X86_64_RELOC_SIGNED_2:
-                                               kind = x86_64::kPCRel32_2;
-                                               addend += 2;
-                                               break;  
-                                       case X86_64_RELOC_SIGNED_4:
-                                               kind = x86_64::kPCRel32_4;
-                                               addend += 4;
-                                               break;
-                               }
-                               makeReferenceToSymbol(kind, srcAddr, targetSymbol, addend);
-                       }
-                       else {
-                               uint64_t ripRelativeOffset = addend;
-                               switch ( reloc->r_type() ) {
-                                       case X86_64_RELOC_SIGNED:
-                                               dstAddr = srcAddr + 4 + ripRelativeOffset;
-                                               kind = x86_64::kPCRel32;
-                                               break;
-                                       case X86_64_RELOC_SIGNED_1:
-                                               dstAddr = srcAddr + 5 + ripRelativeOffset;
-                                               kind = x86_64::kPCRel32_1;
-                                               break;  
-                                       case X86_64_RELOC_SIGNED_2:
-                                               dstAddr = srcAddr + 6 + ripRelativeOffset;
-                                               kind = x86_64::kPCRel32_2;
-                                               break;  
-                                       case X86_64_RELOC_SIGNED_4:
-                                               dstAddr = srcAddr + 8 + ripRelativeOffset;
-                                               kind = x86_64::kPCRel32_4;
-                                               break;
-                               }
-                               makeReference(kind, srcAddr, dstAddr);
-                               // verify that dstAddr is in the section being targeted
-                               int sectNum = reloc->r_symbolnum();
-                               const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)fSegment + sizeof(macho_segment_command<P>));
-                               const macho_section<P>* const targetSection = &sectionsStart[sectNum-1];
-                               if ( (dstAddr < targetSection->addr()) || (dstAddr > (targetSection->addr()+targetSection->size())) ) {
-                                       throwf("local relocation for address 0x%08llX in section %s does not target section %s", 
-                                                       srcAddr, sect->sectname(), targetSection->sectname());
-                               }
-                       }       
-                       break;
-               case X86_64_RELOC_BRANCH:
-                       if ( ! reloc->r_pcrel() )
-                               throw "not pcrel and X86_64_RELOC_BRANCH not supported";
-                       if ( reloc->r_length() == 2 ) {
-                               dstAddr = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
-                               if ( reloc->r_extern() ) {
-                                       if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
-                                               makeByNameReference(x86_64::kDtraceProbeSite, srcAddr, targetName, 0);
-                                               addDtraceExtraInfos(srcAddr, &targetName[16]);
-                                       }
-                                       else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
-                                               makeByNameReference(x86_64::kDtraceIsEnabledSite, srcAddr, targetName, 0);
-                                               addDtraceExtraInfos(srcAddr, &targetName[16]);
-                                       }
-                                       else if ( isWeakImportSymbol(targetSymbol) )
-                                               makeReferenceToSymbol(x86_64::kBranchPCRel32WeakImport, srcAddr, targetSymbol, dstAddr);
-                                       else
-                                               makeReferenceToSymbol(x86_64::kBranchPCRel32, srcAddr, targetSymbol, dstAddr);
-                               }
-                               else {
-                                       makeReference(x86_64::kBranchPCRel32, srcAddr, srcAddr+4+dstAddr);
-                               }
-                       }
-                       else if ( reloc->r_length() == 0 ) {
-                               dstAddr = *((int8_t*)fixUpPtr);
-                               if ( reloc->r_extern() ) {
-                                       makeReferenceToSymbol(x86_64::kBranchPCRel8, srcAddr, targetSymbol, dstAddr);
-                               }
-                               else {
-                                       makeReference(x86_64::kBranchPCRel8, srcAddr, srcAddr+1+dstAddr);
-                               }
-                       }
-                       else {
-                               throwf("length=%d and X86_64_RELOC_BRANCH not supported", reloc->r_length());;
-                       }
-                       break;
-               case X86_64_RELOC_GOT:
-                       if ( ! reloc->r_extern() ) 
-                               throw "not extern and X86_64_RELOC_GOT not supported";
-                       if ( ! reloc->r_pcrel() )
-                               throw "not pcrel and X86_64_RELOC_GOT not supported";
-                       if ( reloc->r_length() != 2 ) 
-                               throw "length != 2 and X86_64_RELOC_GOT not supported";
-                       addend = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
-                       if ( isWeakImportSymbol(targetSymbol) )
-                               makeReferenceToSymbol(x86_64::kPCRel32GOTWeakImport, srcAddr, targetSymbol, addend);
-                       else
-                               makeReferenceToSymbol(x86_64::kPCRel32GOT, srcAddr, targetSymbol, addend);
-                       break;
-               case X86_64_RELOC_GOT_LOAD:
-                       if ( ! reloc->r_extern() ) 
-                               throw "not extern and X86_64_RELOC_GOT_LOAD not supported";
-                       if ( ! reloc->r_pcrel() )
-                               throw "not pcrel and X86_64_RELOC_GOT_LOAD not supported";
-                       if ( reloc->r_length() != 2 ) 
-                               throw "length != 2 and X86_64_RELOC_GOT_LOAD not supported";
-                       addend = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
-                       if ( isWeakImportSymbol(targetSymbol) )
-                               makeReferenceToSymbol(x86_64::kPCRel32GOTLoadWeakImport, srcAddr, targetSymbol, addend);
-                       else
-                               makeReferenceToSymbol(x86_64::kPCRel32GOTLoad, srcAddr, targetSymbol, addend);
-                       break;
-               case X86_64_RELOC_SUBTRACTOR:
-               {
-                       if ( reloc->r_pcrel() )
-                               throw "X86_64_RELOC_SUBTRACTOR cannot be pc-relative";
-                       if ( reloc->r_length() < 2 )
-                               throw "X86_64_RELOC_SUBTRACTOR must have r_length of 2 or 3";
-                       if ( !reloc->r_extern() )
-                               throw "X86_64_RELOC_SUBTRACTOR must have r_extern=1";
-                       const macho_relocation_info<x86_64::P>* nextReloc = &reloc[1];
-                       if ( nextReloc->r_type() != X86_64_RELOC_UNSIGNED )
-                               throw "X86_64_RELOC_SUBTRACTOR must be followed by X86_64_RELOC_UNSIGNED";
-                       result = true;
-                       if ( nextReloc->r_pcrel() )
-                               throw "X86_64_RELOC_UNSIGNED following a X86_64_RELOC_SUBTRACTOR cannot be pc-relative";
-                       if ( nextReloc->r_length() != reloc->r_length() )
-                               throw "X86_64_RELOC_UNSIGNED following a X86_64_RELOC_SUBTRACTOR must have same r_length";
-                       Reference<x86_64>* ref;
-                       bool negativeAddend;
-                       if ( reloc->r_length() == 2 ) {
-                               kind = x86_64::kPointerDiff32;
-                               dstAddr = E::get32(*fixUpPtr); // addend is in content
-                               negativeAddend = ((dstAddr & 0x80000000) != 0);
-                       }
-                       else {
-                               kind = x86_64::kPointerDiff;
-                               dstAddr = E::get64(*((uint64_t*)fixUpPtr)); // addend is in content
-                               negativeAddend = ((dstAddr & 0x8000000000000000ULL) != 0);
-                       }
-                       AtomAndOffset inAtomAndOffset = this->findAtomAndOffset(srcAddr);
-                       ObjectFile::Atom* inAtom = inAtomAndOffset.atom;
-                       // create reference with "to" target
-                       if ( nextReloc->r_extern() ) {
-                               const macho_nlist<P>* targetSymbol = &fSymbols[nextReloc->r_symbolnum()];
-                               const char* targetName = &fStrings[targetSymbol->n_strx()];
-                               ref = makeReferenceToSymbol(kind, srcAddr, targetSymbol, 0);
-                               // if "to" is in this atom, change by-name to a direct reference
-                               if ( strcmp(targetName, inAtom->getName()) == 0 )
-                                       ref->setTarget(*inAtom, 0);
-                       }
-                       else {
-                               ref = makeReference(kind, srcAddr, dstAddr);
-                       }
-                       // add in "from" target
-                       if ( reloc->r_extern() ) {
-                               const macho_nlist<P>* targetFromSymbol = &fSymbols[reloc->r_symbolnum()];
-                               const char* fromTargetName = &fStrings[targetFromSymbol->n_strx()];
-                               if ( (targetFromSymbol->n_type() & N_EXT) == 0 ) {
-                                       // from target is translation unit scoped, so use a direct reference
-                                       ref->setFromTarget(*(findAtomAndOffset(targetSymbol->n_value()).atom));
-                               }
-                               else if ( strcmp(fromTargetName, inAtom->getName()) == 0 ) {
-                                       // if "from" is in this atom, change by-name to a direct reference
-                                       ref->setFromTarget(*inAtom);
-                               }
-                               else {
-                                       // some non-static other atom
-                                       ref->setFromTargetName(fromTargetName);
-                               }
-                       }
-                       else {
-                               throw "X86_64_RELOC_SUBTRACTOR not supported with r_extern=0";
-                       }
-                       // addend goes in from side iff negative
-                       if ( negativeAddend )
-                               ref->setFromTargetOffset(-dstAddr);
-                       else
-                               ref->setToTargetOffset(dstAddr);
-                       break;
-               }
-               default:
-                       warning("unknown relocation type %d", reloc->r_type());
-       }
-       return result;
-}
-
-
-/// Reader<arm>::addRelocReference - 
-/// turns arm relocation entries into references.  Returns true if the next
-/// relocation should be skipped, false otherwise.
-template <>
-bool Reader<arm>::addRelocReference(const macho_section<arm::P>* sect, 
-                                    const macho_relocation_info<arm::P>* reloc)
-{
-       uint32_t *  fixUpPtr;
-       int32_t         displacement;                                                                                           
-       uint32_t    instruction = 0;
-       bool        result = false;
-       uint32_t        srcAddr;
-       uint32_t        dstAddr;
-       uint32_t        pointerValue;
-       arm::ReferenceKinds kind = arm::kNoFixUp;
-       
-       if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
-               // non-scattered relocation
-               const char* targetName = NULL;
-               bool        weakImport = false;
-    
-               srcAddr = sect->addr() + reloc->r_address();
-               fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
-               if ( reloc->r_type() != ARM_RELOC_PAIR )
-                       instruction = LittleEndian::get32(*fixUpPtr);
-    
-               if ( reloc->r_extern() ) {
-                       const macho_nlist<P>* targetSymbol = &fSymbols[reloc->r_symbolnum()];
-                       targetName = &fStrings[targetSymbol->n_strx()];
-                       weakImport = this->isWeakImportSymbol(targetSymbol);
-               }
-    
-               switch ( reloc->r_type() ) {
-                       case ARM_RELOC_BR24:
-                               // Sign-extend displacement
-                               displacement = (instruction & 0x00FFFFFF) << 2;
-                               if ( (displacement & 0x02000000) != 0 )
-                                       displacement |= 0xFC000000;
-                               // The pc added will be +8 from the pc
-                               displacement += 8;
-                               // If this is BLX add H << 1
-                               if ((instruction & 0xFE000000) == 0xFA000000)
-                                       displacement += ((instruction & 0x01000000) >> 23);
-
-                               if ( reloc->r_extern() ) {
-                                       uint32_t offsetInTarget = srcAddr + displacement;
-                                       if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
-                                               makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0);
-                                               addDtraceExtraInfos(srcAddr, &targetName[16]);
-                                       }
-                                       else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
-                                               makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0);
-                                               addDtraceExtraInfos(srcAddr, &targetName[20]);
-                                       }
-                                       else if ( weakImport )
-                                               makeByNameReference(arm::kBranch24WeakImport, srcAddr, targetName, offsetInTarget);
-                                       else
-                                               makeByNameReference(arm::kBranch24, srcAddr, targetName, offsetInTarget);
-                               }
-                               else {
-                                       dstAddr = srcAddr + displacement;
-                                       ObjectFile::Atom* atom = findAtomAndOffset(dstAddr).atom;
-                                       // check for dtrace probes and weak_import stubs 
-                                       const char* targetName = atom->getName();
-                                       if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) {
-                                               makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0);
-                                               addDtraceExtraInfos(srcAddr, &targetName[16]);
-                                       }
-                                       else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) {
-                                               makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0);
-                                               addDtraceExtraInfos(srcAddr, &targetName[20]);
-                                       }
-                                       else if ( (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
-                                               && ((AnonymousAtom<x86>*)atom)->isWeakImportStub() )
-                                               makeReference(arm::kBranch24WeakImport, srcAddr, dstAddr);
-                                       else if ( reloc->r_symbolnum() != R_ABS )
-                                               makeReference(arm::kBranch24, srcAddr, dstAddr);
-                                       else {
-                                               // find absolute symbol that corresponds to pointerValue
-                                               AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
-                                               if ( pos != fAddrToAbsoluteAtom.end() ) 
-                                                       makeByNameReference(arm::kBranch24, srcAddr, pos->second->getName(), 0);
-                                               else
-                                                       throwf("R_ABS reloc but no absolute symbol at target address");
-                                       }
-                               }
-                               break;
-       
-                       case ARM_THUMB_RELOC_BR22:
-                               // thumb2 added two more bits to displacement, complicating the displacement decoding
-                               {
-                                       uint32_t s = (instruction >> 10) & 0x1;
-                                       uint32_t j1 = (instruction >> 29) & 0x1;
-                                       uint32_t j2 = (instruction >> 27) & 0x1;
-                                       uint32_t imm10 = instruction & 0x3FF;
-                                       uint32_t imm11 = (instruction >> 16) & 0x7FF;
-                                       uint32_t i1 = (j1 == s);
-                                       uint32_t i2 = (j2 == s);
-                                       uint32_t dis = (s << 24) | (i1 << 23) | (i2 << 22) | (imm10 << 12) | (imm11 << 1);
-                                       int32_t sdis = dis;
-                                       if ( s )
-                                               sdis |= 0xFE000000;
-                                       displacement = sdis;
-                               }
-                               // The pc added will be +4 from the pc
-                               displacement += 4;
-                               // If the instruction was blx, force the low 2 bits to be clear
-                               dstAddr = srcAddr + displacement;
-                               if ((instruction & 0xF8000000) == 0xE8000000)
-                                       dstAddr &= 0xFFFFFFFC;
-
-                               if ( reloc->r_extern() ) {
-                                       uint32_t offsetInTarget = dstAddr;
-                                       if ( strncmp(targetName, "___dtrace_probe$", 16) == 0 ) {
-                                               makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0);
-                                               addDtraceExtraInfos(srcAddr, &targetName[16]);
-                                       }
-                                       else if ( strncmp(targetName, "___dtrace_isenabled$", 20) == 0 ) {
-                                               makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0);
-                                               addDtraceExtraInfos(srcAddr, &targetName[20]);
-                                       }
-                                       else if ( weakImport )
-                                               makeByNameReference(arm::kThumbBranch22WeakImport, srcAddr, targetName, offsetInTarget);
-                                       else
-                                               makeByNameReference(arm::kThumbBranch22, srcAddr, targetName, offsetInTarget);
-                               }
-                               else {
-                                       ObjectFile::Atom* atom = findAtomAndOffset(dstAddr).atom;
-                                       // check for dtrace probes and weak_import stubs 
-                                       const char* targetName = atom->getName();
-                                       if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_probe$", 16) == 0) ) {
-                                               makeByNameReference(arm::kDtraceProbeSite, srcAddr, targetName, 0);
-                                               addDtraceExtraInfos(srcAddr, &targetName[16]);
-                                       }
-                                       else if ( (targetName != NULL) && (strncmp(targetName, "___dtrace_isenabled$", 20) == 0) ) {
-                                               makeByNameReference(arm::kDtraceIsEnabledSite, srcAddr, targetName, 0);
-                                               addDtraceExtraInfos(srcAddr, &targetName[20]);
-                                       }
-                                       else if ( (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
-                                               && ((AnonymousAtom<x86>*)atom)->isWeakImportStub() )
-                                               makeReference(arm::kThumbBranch22WeakImport, srcAddr, dstAddr);
-                                       else if ( reloc->r_symbolnum() != R_ABS )
-                                               makeReference(arm::kThumbBranch22, srcAddr, dstAddr);
-                                       else {
-                                               // find absolute symbol that corresponds to pointerValue
-                                               AddrToAtomMap::iterator pos = fAddrToAbsoluteAtom.find(dstAddr);
-                                               if ( pos != fAddrToAbsoluteAtom.end() ) 
-                                                       makeByNameReference(arm::kThumbBranch22, srcAddr, pos->second->getName(), 0);
-                                               else
-                                                       throwf("R_ABS reloc but no absolute symbol at target address");
-                                       }
-                               }
-                               break;
-
-                       case ARM_RELOC_VANILLA:
-                               if ( reloc->r_length() != 2 )
-                                       throw "bad length for ARM_RELOC_VANILLA";
-
-                               pointerValue = instruction;
-                               kind = arm::kPointer;
-                               if ( strcmp(sect->segname(), "__TEXT") == 0 )
-                                       kind = arm::kReadOnlyPointer;
-                               if ( weakImport )
-                                       kind = arm::kPointerWeakImport;
-                               if ( reloc->r_extern() ) {
-                                       const macho_nlist<P>* targetSymbol = &fSymbols[reloc->r_symbolnum()];
-                                       if ( (targetSymbol->n_desc() &  N_ARM_THUMB_DEF) && (pointerValue == 1) )
-                                               pointerValue = 0;
-                                       makeByNameReference(kind, srcAddr, targetName, pointerValue);
-                               }
-                               else {
-                                       AtomAndOffset at = findAtomAndOffset(srcAddr);
-                                       AtomAndOffset to = findAtomAndOffsetForSection(pointerValue, reloc->r_symbolnum());
-                                       if ( to.atom->isThumb() )
-                                               to.offset &= -2;
-                                       new Reference<arm>(kind, at, to);
-                               }
-                               break;
-                               
-                       case ARM_THUMB_32BIT_BRANCH:
-                               // ignore old unnecessary relocs
-                               break;
-                               
-                       default:
-                               warning("unexpected relocation type %u", reloc->r_type());
-                               break;
-               }
-       } 
-       else {
-               const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
-               const macho_scattered_relocation_info<P>* nextSReloc = &sreloc[1];
-               int32_t addend;
-               srcAddr = sect->addr() + sreloc->r_address();
-               dstAddr = sreloc->r_value();
-               uint32_t betterDstAddr;
-               fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + sreloc->r_address());
-               instruction = LittleEndian::get32(*fixUpPtr);
-               
-               // A ARM_RELOC_PAIR only follows ARM_RELOC_{SECTDIFF,LOCAL_SECTDIFF}
-               // relocation types, and it is an error to see one otherwise.
-               bool nextRelocIsPair = false;
-               uint32_t nextRelocAddress = 0;
-               uint32_t nextRelocValue = 0;
-               if ( nextSReloc->r_type() == ARM_RELOC_PAIR ) {
-                       nextRelocIsPair = true;
-                       nextRelocAddress = nextSReloc->r_address();
-                       nextRelocValue = nextSReloc->r_value();
-                       result = true;
-               }
-               
-               switch (sreloc->r_type()) {
-                       case ARM_RELOC_VANILLA:
-                               if ( sreloc->r_length() != 2 )
-                                       throw "bad length for ARM_RELOC_VANILLA";
-
-                               //fprintf(stderr, "scattered pointer reloc: srcAddr=0x%08X, dstAddr=0x%08X, pointer=0x%08X\n", srcAddr, dstAddr, betterDstAddr);
-                               betterDstAddr = LittleEndian::get32(*fixUpPtr);
-                               kind = arm::kPointer;
-                               if ( strcmp(sect->segname(), "__TEXT") == 0 )
-                                       kind = arm::kReadOnlyPointer;
-                               // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
-                               makeReferenceWithToBase(kind, srcAddr, betterDstAddr, dstAddr);
-                               break;
-               
-                       case ARM_RELOC_BR24:
-                               // Sign-extend displacement
-                               displacement = (instruction & 0x00FFFFFF) << 2;
-                               if ( (displacement & 0x02000000) != 0 )
-                                       displacement |= 0xFC000000;
-                               // The pc added will be +8 from the pc
-                               displacement += 8;
-                               // If this is BLX add H << 1
-                               if ((instruction & 0xFE000000) == 0xFA000000)
-                                       displacement += ((instruction & 0x01000000) >> 23);
-                               betterDstAddr = srcAddr+displacement;
-                               makeReferenceWithToBase(arm::kBranch24, srcAddr, betterDstAddr, dstAddr);
-                               break;
-               
-                       case ARM_THUMB_RELOC_BR22:
-                               // thumb2 added two more bits to displacement, complicating the displacement decoding
-                               {
-                                       uint32_t s = (instruction >> 10) & 0x1;
-                                       uint32_t j1 = (instruction >> 29) & 0x1;
-                                       uint32_t j2 = (instruction >> 27) & 0x1;
-                                       uint32_t imm10 = instruction & 0x3FF;
-                                       uint32_t imm11 = (instruction >> 16) & 0x7FF;
-                                       uint32_t i1 = (j1 == s);
-                                       uint32_t i2 = (j2 == s);
-                                       uint32_t dis = (s << 24) | (i1 << 23) | (i2 << 22) | (imm10 << 12) | (imm11 << 1);
-                                       int32_t sdis = dis;
-                                       if ( s )
-                                               sdis |= 0xFE000000;
-                                       displacement = sdis;
-                               }
-                               // The pc added will be +4 from the pc
-                               displacement += 4;
-                               betterDstAddr = srcAddr+displacement;
-                               // If the instruction was blx, force the low 2 bits to be clear
-                               if ((instruction & 0xF8000000) == 0xE8000000)
-                                       betterDstAddr &= 0xFFFFFFFC;
-                               makeReferenceWithToBase(arm::kThumbBranch22, srcAddr, betterDstAddr, dstAddr);
-                               break;
-               
-                       case ARM_RELOC_SECTDIFF:
-                       case ARM_RELOC_LOCAL_SECTDIFF:
-                               if ( !nextRelocIsPair ) {
-                                       throw "ARM_RELOC_SECTDIFF missing following pair";
-                               }
-                               if ( sreloc->r_length() != 2 )
-                                       throw "bad length for ARM_RELOC_SECTDIFF";
-                               {
-                               AtomAndOffset srcao  = findAtomAndOffset(srcAddr);
-                               AtomAndOffset fromao = findAtomAndOffset(nextRelocValue);
-                               AtomAndOffset toao   = findAtomAndOffset(dstAddr);
-                               // check for addend encoded in the section content
-                               pointerValue = LittleEndian::get32(*fixUpPtr);
-                               addend = pointerValue - (dstAddr - nextRelocValue);
-                               if ( toao.atom->isThumb() && (addend & 1) )
-                                       addend &= -2; // remove thumb bit 
-                               if ( (dstAddr - nextRelocValue) != pointerValue ) {
-                                       if ( fromao.atom == srcao.atom ) {
-                                               if ( ((const macho_section<P>*)(((BaseAtom*)(srcao.atom))->getSectionRecord()))->flags() & S_ATTR_PURE_INSTRUCTIONS ) {
-                                                       int pcBaseOffset = srcao.atom->isThumb() ? 4 : 8;
-                                                       if ( addend == -pcBaseOffset ) {
-                                                               fromao.offset -= addend;
-                                                       }
-                                                       else {
-                                                               toao.offset += addend;
-                                                       }
-                                               }
-                                               else {
-                                                       toao.offset += addend;
-                                               }
-                                       }
-                                       else if ( toao.atom == srcao.atom )
-                                               toao.offset += addend;
-                                       else
-                                               fromao.offset -= addend;
-                               }
-                               new Reference<arm>(arm::kPointerDiff, srcao, fromao, toao);
-                               }
-                               break;
-                       
-                       default:
-                               warning("unexpected srelocation type %u", sreloc->r_type());
-                               break;
-               }
-       }
-       return result;
-}
-
-template <typename A>
-void Reader<A>::addReferencesForSection(const macho_section<P>* sect)
-{
-       // ignore dwarf sections.  If ld ever supports processing dwarf, this logic will need to change
-       if ( (sect->flags() & S_ATTR_DEBUG) == 0 ) {
-               switch ( sect->flags() & SECTION_TYPE ) {
-                       case S_SYMBOL_STUBS:
-                       case S_LAZY_SYMBOL_POINTERS:
-                               // we ignore compiler generated stubs, so ignore those relocs too
-                               break;
-                       default:
-                               // ignore all relocations in __eh_frame section
-                               if ( sect == fehFrameSection )
-                                       return;
-                               const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fHeader) + sect->reloff());
-                               const uint32_t relocCount = sect->nreloc();
-                               //fprintf(stderr, "relocCount = %d in section %s\n", relocCount, sect->sectname());
-                               for (uint32_t r = 0; r < relocCount; ++r) {
-                                       try {
-                                               if ( addRelocReference(sect, &relocs[r]) )
-                                                       ++r; // skip next
-                                       }
-                                       catch (const char* msg) {
-                                               throwf("in section %s,%s reloc %u: %s", sect->segname(), sect->sectname(), r, msg);
-                                       }
-                               }
-               }
-       }
-}
-
-
-template <>
-const char* Reference<x86>::getDescription() const
-{
-       static char temp[2048];
-       switch( fKind ) {
-               case x86::kNoFixUp:
-                       sprintf(temp, "reference to ");
-                       break;
-               case x86::kFollowOn:
-                       sprintf(temp, "followed by ");
-                       break;
-               case x86::kGroupSubordinate:
-                       sprintf(temp, "group subordinate ");
-                       break;
-               case x86::kPointerWeakImport:
-                       sprintf(temp, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc);
-                       break;
-               case x86::kPointer:
-                       sprintf(temp, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc);
-                       break;
-               case x86::kPointerDiff:
-                       {
-                       // by-name references have quoted names
-                       const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
-                       const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
-                       sprintf(temp, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)",
-                               fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
-                                                          fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
-                       return temp;
-                       }
-                       break;
-               case x86::kPointerDiff16:
-                       {
-                       // by-name references have quoted names
-                       const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
-                       const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
-                       sprintf(temp, "offset 0x%04X, 16-bit pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)",
-                               fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
-                                                          fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
-                       return temp;
-                       }
-                       break;
-               case x86::kPCRel32WeakImport:
-                       sprintf(temp, "offset 0x%04X, rel32 reference to weak imported ", fFixUpOffsetInSrc);
-                       break;
-               case x86::kPCRel32:
-                       sprintf(temp, "offset 0x%04X, rel32 reference to ", fFixUpOffsetInSrc);
-                       break;
-               case x86::kPCRel16:
-                       sprintf(temp, "offset 0x%04X, rel16 reference to ", fFixUpOffsetInSrc);
-                       break;
-               case x86::kPCRel8:
-                       sprintf(temp, "offset 0x%04X, rel8 reference to ", fFixUpOffsetInSrc);
-                       break;
-               case x86::kAbsolute32:
-                       sprintf(temp, "offset 0x%04X, absolute32 reference to ", fFixUpOffsetInSrc);
-                       break;
-               case x86::kImageOffset32:
-                       sprintf(temp, "offset 0x%04X, 32-bit offset of ", fFixUpOffsetInSrc);
-                       break;
-               case x86::kPointerDiff24:
-                       sprintf(temp, "offset 0x%04X, 24-bit pointer difference: (&%s + 0x%08X) - (&%s + 0x%08X)",
-                               fFixUpOffsetInSrc, this->getTargetDisplayName(), fToTarget.offset,
-                                                          this->getFromTargetDisplayName(), fFromTarget.offset );
-                       return temp;
-                       break;
-               case x86::kSectionOffset24:
-                       sprintf(temp, "offset 0x%04X, 24-bit section offset of ", fFixUpOffsetInSrc);
-                       break;
-               case x86::kDtraceProbe:
-                       sprintf(temp, "offset 0x%04X, dtrace static probe ", fFixUpOffsetInSrc);
-                       break;
-               case x86::kDtraceProbeSite:
-                       sprintf(temp, "offset 0x%04X, dtrace static probe site", fFixUpOffsetInSrc);
-                       break;
-               case x86::kDtraceIsEnabledSite:
-                       sprintf(temp, "offset 0x%04X, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
-                       break;
-               case x86::kDtraceTypeReference:
-                       sprintf(temp, "offset 0x%04X, dtrace type/stability reference", fFixUpOffsetInSrc);
-                       break;
-       }
-       // always quote by-name references
-       if ( fToTargetName != NULL ) {
-               strcat(temp, "\"");
-               strcat(temp, fToTargetName);
-               strcat(temp, "\"");
-       }
-       else if ( fToTarget.atom != NULL ) {
-               strcat(temp, fToTarget.atom->getDisplayName());
-       }
-       else {
-               strcat(temp, "NULL target");
-       }
-       if ( fToTarget.offset != 0 )
-               sprintf(&temp[strlen(temp)], " plus 0x%08X", fToTarget.offset);
-
-       return temp;
-}
-
-
-template <>
-const char* Reference<ppc>::getDescription() const
-{
-       static char temp[2048];
-       switch( fKind ) {
-               case ppc::kNoFixUp:
-                       sprintf(temp, "reference to ");
-                       break;
-               case ppc::kFollowOn:
-                       sprintf(temp, "followed by ");
-                       break;
-               case ppc::kGroupSubordinate:
-                       sprintf(temp, "group subordinate ");
-                       break;
-               case ppc::kPointerWeakImport:
-                       sprintf(temp, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc);
-                       break;
-               case ppc::kPointer:
-                       sprintf(temp, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc);
-                       break;
-               case ppc::kPointerDiff16:
-                       {
-                       // by-name references have quoted names
-                       const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
-                       const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
-                       sprintf(temp, "offset 0x%04X, 16-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)",
-                               fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
-                                                          fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
-                       return temp;
-                       }
-               case ppc::kPointerDiff32:
-                       {
-                       // by-name references have quoted names
-                       const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
-                       const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
-                       sprintf(temp, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)",
-                               fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
-                                                          fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
-                       return temp;
-                       }
-               case ppc::kPointerDiff64:
-                       throw "unsupported refrence kind";
-                       break;
-               case ppc::kBranch24WeakImport:
-                       sprintf(temp, "offset 0x%04X, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc);
-                       break;
-               case ppc::kBranch24:
-               case ppc::kBranch14:
-                       sprintf(temp, "offset 0x%04X, pc-rel branch fixup to ", fFixUpOffsetInSrc);
-                       break;
-               case ppc::kPICBaseLow16:
-                       sprintf(temp, "offset 0x%04X, low  16 fixup from pic-base of %s plus 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.atom->getDisplayName(), fFromTarget.offset);
-                       break;
-               case ppc::kPICBaseLow14:
-                       sprintf(temp, "offset 0x%04X, low  14 fixup from pic-base of %s plus 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.atom->getDisplayName(), fFromTarget.offset);
-                       break;
-               case ppc::kPICBaseHigh16:
-                       sprintf(temp, "offset 0x%04X, high 16 fixup from pic-base of %s plus 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.atom->getDisplayName(), fFromTarget.offset);
-                       break;
-               case ppc::kAbsLow16:
-                       sprintf(temp, "offset 0x%04X, low  16 fixup to absolute address of ", fFixUpOffsetInSrc);
-                       break;
-               case ppc::kAbsLow14:
-                       sprintf(temp, "offset 0x%04X, low  14 fixup to absolute address of ", fFixUpOffsetInSrc);
-                       break;
-               case ppc::kAbsHigh16:
-                       sprintf(temp, "offset 0x%04X, high 16 fixup or to absolute address of ", fFixUpOffsetInSrc);
-                       break;
-               case ppc::kAbsHigh16AddLow:
-                       sprintf(temp, "offset 0x%04X, high 16 fixup add to absolute address of ", fFixUpOffsetInSrc);
-                       break;
-               case ppc::kDtraceProbe:
-                       sprintf(temp, "offset 0x%04X, dtrace static probe ", fFixUpOffsetInSrc);
-                       break;
-               case ppc::kDtraceProbeSite:
-                       sprintf(temp, "offset 0x%04X, dtrace static probe site", fFixUpOffsetInSrc);
-                       break;
-               case ppc::kDtraceIsEnabledSite:
-                       sprintf(temp, "offset 0x%04X, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
-                       break;
-               case ppc::kDtraceTypeReference:
-                       sprintf(temp, "offset 0x%04X, dtrace type/stability reference", fFixUpOffsetInSrc);
-                       break;
-       }
-       // always quote by-name references
-       if ( fToTargetName != NULL ) {
-               strcat(temp, "\"");
-               strcat(temp, fToTargetName);
-               strcat(temp, "\"");
-       }
-       else if ( fToTarget.atom != NULL ) {
-               strcat(temp, fToTarget.atom->getDisplayName());
-       }
-       else {
-               strcat(temp, "NULL target");
-       }
-       if ( fToTarget.offset != 0 )
-               sprintf(&temp[strlen(temp)], " plus 0x%08X", fToTarget.offset);
-
-       return temp;
-}
-
-template <>
-const char* Reference<ppc64>::getDescription() const
-{
-       static char temp[2048];
-       switch( fKind ) {
-               case ppc64::kNoFixUp:
-                       sprintf(temp, "reference to ");
-                       break;
-               case ppc64::kFollowOn:
-                       sprintf(temp, "followed by ");
-                       break;
-               case ppc64::kGroupSubordinate:
-                       sprintf(temp, "group subordinate ");
-                       break;
-               case ppc64::kPointerWeakImport:
-                       sprintf(temp, "offset 0x%04llX, weak import pointer to ", fFixUpOffsetInSrc);
-                       break;
-               case ppc64::kPointer:
-                       sprintf(temp, "offset 0x%04llX, pointer to ", fFixUpOffsetInSrc);
-                       break;
-               case ppc64::kPointerDiff64:
-                       {
-                       // by-name references have quoted names
-                       const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
-                       const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
-                       sprintf(temp, "offset 0x%04llX, 64-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)",
-                               fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
-                                                          fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
-                       return temp;
-                       }
-               case ppc64::kPointerDiff32:
-                       {
-                       // by-name references have quoted names
-                       const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
-                       const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
-                       sprintf(temp, "offset 0x%04llX, 32-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)",
-                               fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
-                                                          fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
-                       return temp;
-                       }
-               case ppc64::kPointerDiff16:
-                       {
-                       // by-name references have quoted names
-                       const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
-                       const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
-                       sprintf(temp, "offset 0x%04llX, 16-bit pointer difference: (&%s%s%s + %u) - (&%s%s%s + %u)",
-                               fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
-                                                          fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
-                       return temp;
-                       }
-               case ppc64::kBranch24WeakImport:
-                       sprintf(temp, "offset 0x%04llX, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc);
-                       break;
-               case ppc64::kBranch24:
-               case ppc64::kBranch14:
-                       sprintf(temp, "offset 0x%04llX, pc-rel branch fixup to ", fFixUpOffsetInSrc);
-                       break;
-               case ppc64::kPICBaseLow16:
-                       sprintf(temp, "offset 0x%04llX, low  16 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
-                       break;
-               case ppc64::kPICBaseLow14:
-                       sprintf(temp, "offset 0x%04llX, low  14 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
-                       break;
-               case ppc64::kPICBaseHigh16:
-                       sprintf(temp, "offset 0x%04llX, high 16 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
-                       break;
-               case ppc64::kAbsLow16:
-                       sprintf(temp, "offset 0x%04llX, low  16 fixup to absolute address of ", fFixUpOffsetInSrc);
-                       break;
-               case ppc64::kAbsLow14:
-                       sprintf(temp, "offset 0x%04llX, low  14 fixup to absolute address of ", fFixUpOffsetInSrc);
-                       break;
-               case ppc64::kAbsHigh16:
-                       sprintf(temp, "offset 0x%04llX, high 16 fixup or to absolute address of ", fFixUpOffsetInSrc);
-                       break;
-               case ppc64::kAbsHigh16AddLow:
-                       sprintf(temp, "offset 0x%04llX, high 16 fixup add to absolute address of ", fFixUpOffsetInSrc);
-                       break;
-               case ppc64::kDtraceProbe:
-                       sprintf(temp, "offset 0x%04llX, dtrace static probe ", fFixUpOffsetInSrc);
-                       break;
-               case ppc64::kDtraceProbeSite:
-                       sprintf(temp, "offset 0x%04llX, dtrace static probe site", fFixUpOffsetInSrc);
-                       break;
-               case ppc64::kDtraceIsEnabledSite:
-                       sprintf(temp, "offset 0x%04llX, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
-                       break;
-               case ppc64::kDtraceTypeReference:
-                       sprintf(temp, "offset 0x%04llX, dtrace type/stability reference", fFixUpOffsetInSrc);
-                       break;
-       }
-       // always quote by-name references
-       if ( fToTargetName != NULL ) {
-               strcat(temp, "\"");
-               strcat(temp, fToTargetName);
-               strcat(temp, "\"");
-       }
-       else if ( fToTarget.atom != NULL ) {
-               strcat(temp, fToTarget.atom->getDisplayName());
-       }
-       else {
-               strcat(temp, "NULL target");
-       }
-       if ( fToTarget.offset != 0 )
-               sprintf(&temp[strlen(temp)], " plus 0x%llX", this->getTargetOffset());
-
-       return temp;
-}
-
-
-template <>
-const char* Reference<x86_64>::getDescription() const
-{
-       static char temp[2048];
-       switch( fKind ) {
-               case x86_64::kNoFixUp:
-                       sprintf(temp, "reference to ");
-                       break;
-               case x86_64::kFollowOn:
-                       sprintf(temp, "followed by ");
-                       break;
-               case x86_64::kGroupSubordinate:
-                       sprintf(temp, "group subordinate ");
-                       break;
-               case x86_64::kPointerWeakImport:
-                       sprintf(temp, "offset 0x%04llX, weak import pointer to ", fFixUpOffsetInSrc);
-                       break;
-               case x86_64::kPointer:
-                       sprintf(temp, "offset 0x%04llX, pointer to ", fFixUpOffsetInSrc);
-                       break;
-               case x86_64::kPointer32:
-                       sprintf(temp, "offset 0x%04llX, 32-bit pointer to ", fFixUpOffsetInSrc);
-                       break;
-               case x86_64::kPointerDiff32:
-               case x86_64::kPointerDiff:
-                       {
-                       // by-name references have quoted names
-                       const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
-                       const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
-                       const char* size = (fKind == x86_64::kPointerDiff32) ? "32-bit" : "64-bit";
-                       sprintf(temp, "offset 0x%04llX, %s pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)",
-                               fFixUpOffsetInSrc, size, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
-                                                          fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
-                       return temp;
-                       }
-                       break;
-               case x86_64::kPCRel32:
-                       sprintf(temp, "offset 0x%04llX, rel32 reference to ", fFixUpOffsetInSrc);
-                       break;
-               case x86_64::kPCRel32_1:
-                       sprintf(temp, "offset 0x%04llX, rel32-1 reference to ", fFixUpOffsetInSrc);
-                       break;
-               case x86_64::kPCRel32_2:
-                       sprintf(temp, "offset 0x%04llX, rel32-2 reference to ", fFixUpOffsetInSrc);
-                       break;
-               case x86_64::kPCRel32_4:
-                       sprintf(temp, "offset 0x%04llX, rel32-4 reference to ", fFixUpOffsetInSrc);
-                       break;
-               case x86_64::kBranchPCRel32:
-                       sprintf(temp, "offset 0x%04llX, branch rel32 reference to ", fFixUpOffsetInSrc);
-                       break;
-               case x86_64::kBranchPCRel32WeakImport:
-                       sprintf(temp, "offset 0x%04llX, branch rel32 reference to weak imported ", fFixUpOffsetInSrc);
-                       break;
-               case x86_64::kPCRel32GOT:
-                       sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for ", fFixUpOffsetInSrc);
-                       break;
-               case x86_64::kPCRel32GOTWeakImport:
-                       sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for weak imported ", fFixUpOffsetInSrc);
-                       break;
-               case x86_64::kPCRel32GOTLoad:
-                       sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for ", fFixUpOffsetInSrc);
-                       break;
-               case x86_64::kPCRel32GOTLoadWeakImport:
-                       sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for weak imported ", fFixUpOffsetInSrc);
-                       break;
-               case x86_64::kGOTNoFixUp:
-                       sprintf(temp, "reference to GOT entry for ");
-                       break;
-               case x86_64::kBranchPCRel8:
-                       sprintf(temp, "offset 0x%04llX, branch rel8 reference to ", fFixUpOffsetInSrc);
-                       break;
-               case x86_64::kPointerDiff24:
-                       sprintf(temp, "offset 0x%04llX, 24-bit pointer difference: (&%s + 0x%08X) - (&%s + 0x%08X)",
-                               fFixUpOffsetInSrc, this->getTargetDisplayName(), fToTarget.offset,
-                                                          this->getFromTargetDisplayName(), fFromTarget.offset );
-                       return temp;
-               case x86_64::kImageOffset32:
-                       sprintf(temp, "offset 0x%04llX, 32bit offset of ", fFixUpOffsetInSrc);
-                       break;
-               case x86_64::kSectionOffset24:
-                       sprintf(temp, "offset 0x%04llX, 24-bit section offset of ", fFixUpOffsetInSrc);
-                       break;
-               case x86_64::kDtraceProbe:
-                       sprintf(temp, "offset 0x%04llX, dtrace static probe ", fFixUpOffsetInSrc);
-                       break;
-               case x86_64::kDtraceProbeSite:
-                       sprintf(temp, "offset 0x%04llX, dtrace static probe site", fFixUpOffsetInSrc);
-                       break;
-               case x86_64::kDtraceIsEnabledSite:
-                       sprintf(temp, "offset 0x%04llX, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
-                       break;
-               case x86_64::kDtraceTypeReference:
-                       sprintf(temp, "offset 0x%04llX, dtrace type/stability reference", fFixUpOffsetInSrc);
-                       break;
-       }
-       // always quote by-name references
-       if ( fToTargetName != NULL ) {
-               strcat(temp, "\"");
-               strcat(temp, fToTargetName);
-               strcat(temp, "\"");
-       }
-       else if ( fToTarget.atom != NULL ) {
-               strcat(temp, fToTarget.atom->getDisplayName());
-       }
-       else {
-               strcat(temp, "NULL target");
-       }
-       if ( fToTarget.offset != 0 )
-               sprintf(&temp[strlen(temp)], " plus 0x%llX", this->getTargetOffset());
-
-       return temp;
-}
-
-
-template <>
-const char* Reference<arm>::getDescription() const
-{
-       static char temp[2048];
-       switch( fKind ) {
-               case arm::kNoFixUp:
-                       sprintf(temp, "reference to ");
-                       break;
-               case arm::kFollowOn:
-                       sprintf(temp, "followed by ");
-                       break;
-               case arm::kGroupSubordinate:
-                       sprintf(temp, "group subordinate ");
-                       break;
-               case arm::kPointer:
-                       sprintf(temp, "offset 0x%04X, pointer to ", fFixUpOffsetInSrc);
-                       break;
-               case arm::kPointerWeakImport:
-                       sprintf(temp, "offset 0x%04X, weak import pointer to ", fFixUpOffsetInSrc);
-                       break;
-               case arm::kPointerDiff:
-                       {
-                       // by-name references have quoted names
-                       const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
-                       const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
-                       sprintf(temp, "offset 0x%04X, 32-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)",
-                               fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
-                                                          fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
-                       return temp;
-                       }
-               case arm::kPointerDiff12:
-                       {
-                       // by-name references have quoted names
-                       const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
-                       const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
-                       sprintf(temp, "offset 0x%04X, 12-bit pointer difference: (&%s%s%s + %d) - (&%s%s%s + %d)",
-                               fFixUpOffsetInSrc, targetQuotes, this->getTargetDisplayName(), targetQuotes, fToTarget.offset,
-                                                          fromQuotes, this->getFromTargetDisplayName(), fromQuotes, fFromTarget.offset );
-                       return temp;
-                       }
-               case arm::kReadOnlyPointer:
-                       sprintf(temp, "offset 0x%04X, read-only pointer to ", fFixUpOffsetInSrc);
-                       break;
-               case arm::kBranch24:
-        case arm::kThumbBranch22:
-                       sprintf(temp, "offset 0x%04X, pc-rel branch fixup to ", fFixUpOffsetInSrc);
-                       break;
-               case arm::kBranch24WeakImport:
-        case arm::kThumbBranch22WeakImport:
-                       sprintf(temp, "offset 0x%04X, pc-rel branch fixup to weak imported ", fFixUpOffsetInSrc);
-                       break;
-               case arm::kDtraceProbe:
-                       sprintf(temp, "offset 0x%04X, dtrace static probe ", fFixUpOffsetInSrc);
-                       break;
-               case arm::kDtraceProbeSite:
-                       sprintf(temp, "offset 0x%04X, dtrace static probe site", fFixUpOffsetInSrc);
-                       break;
-               case arm::kDtraceIsEnabledSite:
-                       sprintf(temp, "offset 0x%04X, dtrace static probe is-enabled site", fFixUpOffsetInSrc);
-                       break;
-               case arm::kDtraceTypeReference:
-                       sprintf(temp, "offset 0x%04X, dtrace type/stability reference", fFixUpOffsetInSrc);
-                       break;
-       }
-       // always quote by-name references
-       if ( fToTargetName != NULL ) {
-               strcat(temp, "\"");
-               strcat(temp, fToTargetName);
-               strcat(temp, "\"");
-       }
-       else if ( fToTarget.atom != NULL ) {
-               strcat(temp, fToTarget.atom->getDisplayName());
-       }
-       else {
-               strcat(temp, "NULL target");
-       }
-       if ( fToTarget.offset != 0 )
-               sprintf(&temp[strlen(temp)], " plus 0x%08X", fToTarget.offset);
-
-       return temp;
-}
-
-
-template <>
-bool Reference<x86>::isBranch() const
-{
-       switch ( fKind ) {
-               case x86::kPCRel32:
-               case x86::kPCRel32WeakImport:
-                       return true;
-               default:
-                       return false;
-       }
-}
-
-template <>
-bool Reference<x86_64>::isBranch() const
-{
-       switch ( fKind ) {
-               case x86_64::kBranchPCRel32:
-               case x86_64::kBranchPCRel32WeakImport:
-                       return true;
-               default:
-                       return false;
-       }
-}
-
-template <>
-bool Reference<ppc>::isBranch() const
-{
-       switch ( fKind ) {
-               case ppc::kBranch24:
-               case ppc::kBranch24WeakImport:
-                       return true;
-               default:
-                       return false;
-       }
-}
-
-template <>
-bool Reference<ppc64>::isBranch() const
-{
-       switch ( fKind ) {
-               case ppc64::kBranch24:
-               case ppc64::kBranch24WeakImport:
-                       return true;
-               default:
-                       return false;
-       }
-}
-
-template <>
-bool Reference<arm>::isBranch() const
-{
-       switch ( fKind ) {
-               case arm::kBranch24:
-               case arm::kBranch24WeakImport:
-               case arm::kThumbBranch22:
-               case arm::kThumbBranch22WeakImport:
-                       return true;
-               default:
-                       return false;
-       }
-}
-
-
-
-}; // namespace relocatable
-}; // namespace mach_o
-
-#endif // __OBJECT_FILE_MACH_O__
diff --git a/src/ld/MachOWriterExecutable.hpp b/src/ld/MachOWriterExecutable.hpp
deleted file mode 100644 (file)
index 5313669..0000000
+++ /dev/null
@@ -1,12114 +0,0 @@
-/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
- *
- * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-#ifndef __EXECUTABLE_MACH_O__
-#define __EXECUTABLE_MACH_O__
-
-#include <stdint.h>
-#include <stddef.h>
-#include <fcntl.h>
-#include <sys/time.h>
-#include <uuid/uuid.h>
-#include <mach/i386/thread_status.h>
-#include <mach/ppc/thread_status.h>
-#include <CommonCrypto/CommonDigest.h>
-
-#include <vector>
-#include <algorithm>
-#include <map>
-#include <set>
-#include <ext/hash_map>
-
-#include "ObjectFile.h"
-#include "ExecutableFile.h"
-#include "Options.h"
-
-#include "MachOFileAbstraction.hpp"
-#include "MachOTrie.hpp"
-
-
-//
-//
-//     To implement architecture xxx, you must write template specializations for the following methods:
-//                     MachHeaderAtom<xxx>::setHeaderInfo()
-//                     ThreadsLoadCommandsAtom<xxx>::getSize()
-//                     ThreadsLoadCommandsAtom<xxx>::copyRawContent()
-//                     Writer<xxx>::addObjectRelocs()
-//                     Writer<xxx>::fixUpReferenceRelocatable()
-//                     Writer<xxx>::fixUpReferenceFinal()
-//                     Writer<xxx>::stubableReference()
-//                     Writer<xxx>::weakImportReferenceKind()
-//                     Writer<xxx>::GOTReferenceKind()
-//
-
-
-namespace mach_o {
-namespace executable {
-
-// forward references
-template <typename A> class WriterAtom;
-template <typename A> class PageZeroAtom;
-template <typename A> class CustomStackAtom;
-template <typename A> class MachHeaderAtom;
-template <typename A> class SegmentLoadCommandsAtom;
-template <typename A> class EncryptionLoadCommandsAtom;
-template <typename A> class SymbolTableLoadCommandsAtom;
-template <typename A> class DyldInfoLoadCommandsAtom;
-template <typename A> class ThreadsLoadCommandsAtom;
-template <typename A> class DylibIDLoadCommandsAtom;
-template <typename A> class RoutinesLoadCommandsAtom;
-template <typename A> class DyldLoadCommandsAtom;
-template <typename A> class UUIDLoadCommandAtom;
-template <typename A> class LinkEditAtom;
-template <typename A> class SectionRelocationsLinkEditAtom;
-template <typename A> class CompressedRebaseInfoLinkEditAtom;
-template <typename A> class CompressedBindingInfoLinkEditAtom;
-template <typename A> class CompressedWeakBindingInfoLinkEditAtom;
-template <typename A> class CompressedLazyBindingInfoLinkEditAtom;
-template <typename A> class CompressedExportInfoLinkEditAtom;
-template <typename A> class LocalRelocationsLinkEditAtom;
-template <typename A> class ExternalRelocationsLinkEditAtom;
-template <typename A> class SymbolTableLinkEditAtom;
-template <typename A> class SegmentSplitInfoLoadCommandsAtom;
-template <typename A> class SegmentSplitInfoContentAtom;
-template <typename A> class IndirectTableLinkEditAtom;
-template <typename A> class ModuleInfoLinkEditAtom;
-template <typename A> class StringsLinkEditAtom;
-template <typename A> class LoadCommandsPaddingAtom;
-template <typename A> class UnwindInfoAtom;
-template <typename A> class StubAtom;
-template <typename A> class StubHelperAtom;
-template <typename A> class ClassicStubHelperAtom;
-template <typename A> class HybridStubHelperAtom;
-template <typename A> class HybridStubHelperHelperAtom;
-template <typename A> class FastStubHelperAtom;
-template <typename A> class FastStubHelperHelperAtom;
-template <typename A> class LazyPointerAtom;
-template <typename A> class NonLazyPointerAtom;
-template <typename A> class DylibLoadCommandsAtom;
-template <typename A> class BranchIslandAtom;
-
-
-// SectionInfo should be nested inside Writer, but I can't figure out how to make the type accessible to the Atom classes
-class SectionInfo : public ObjectFile::Section {
-public:
-                                                                               SectionInfo() : fFileOffset(0), fSize(0), fRelocCount(0), fRelocOffset(0), 
-                                                                                                               fIndirectSymbolOffset(0), fAlignment(0), fAllLazyPointers(false), 
-                                                                                                               fAllLazyDylibPointers(false),fAllNonLazyPointers(false), fAllStubs(false),
-                                                                                                               fAllSelfModifyingStubs(false), fAllStubHelpers(false),
-                                                                                                               fAllZeroFill(false), fVirtualSection(false),
-                                                                                                               fHasTextLocalRelocs(false), fHasTextExternalRelocs(false)
-                                                                                                               { fSegmentName[0] = '\0'; fSectionName[0] = '\0'; }
-       void                                                            setIndex(unsigned int index) { fIndex=index; }
-       std::vector<ObjectFile::Atom*>          fAtoms;
-       char                                                            fSegmentName[20];
-       char                                                            fSectionName[20];
-       uint64_t                                                        fFileOffset;
-       uint64_t                                                        fSize;
-       uint32_t                                                        fRelocCount;
-       uint32_t                                                        fRelocOffset;
-       uint32_t                                                        fIndirectSymbolOffset;
-       uint8_t                                                         fAlignment;
-       bool                                                            fAllLazyPointers;
-       bool                                                            fAllLazyDylibPointers;
-       bool                                                            fAllNonLazyPointers;
-       bool                                                            fAllStubs;
-       bool                                                            fAllSelfModifyingStubs;
-       bool                                                            fAllStubHelpers;
-       bool                                                            fAllZeroFill;
-       bool                                                            fVirtualSection;
-       bool                                                            fHasTextLocalRelocs;
-       bool                                                            fHasTextExternalRelocs;
-};
-
-// SegmentInfo should be nested inside Writer, but I can't figure out how to make the type accessible to the Atom classes
-class SegmentInfo
-{
-public:
-                                                                               SegmentInfo(uint64_t pageSize) : fInitProtection(0), fMaxProtection(0), fFileOffset(0), fFileSize(0),
-                                                                                                               fBaseAddress(0), fSize(0), fPageSize(pageSize), fFixedAddress(false), 
-                                                                                                               fIndependentAddress(false), fHasLoadCommand(true) { fName[0] = '\0'; }
-       std::vector<class SectionInfo*>         fSections;
-       char                                                            fName[20];
-       uint32_t                                                        fInitProtection;
-       uint32_t                                                        fMaxProtection;
-       uint64_t                                                        fFileOffset;
-       uint64_t                                                        fFileSize;
-       uint64_t                                                        fBaseAddress;
-       uint64_t                                                        fSize;
-       uint64_t                                                        fPageSize;
-       bool                                                            fFixedAddress;
-       bool                                                            fIndependentAddress;
-       bool                                                            fHasLoadCommand;
-};
-
-
-struct RebaseInfo {
-                                       RebaseInfo(uint8_t t, uint64_t addr) : fType(t), fAddress(addr) {}
-       uint8_t                 fType;
-       uint64_t                fAddress;
-       // for sorting
-       int operator<(const RebaseInfo& rhs) const {
-               // sort by type, then address
-               if ( this->fType != rhs.fType )
-                       return  (this->fType < rhs.fType );
-               return  (this->fAddress < rhs.fAddress );
-       }
-};
-
-struct BindingInfo {
-                                       BindingInfo(uint8_t t, int ord, const char* sym, bool weak_import, uint64_t addr, int64_t addend) 
-                                               : fType(t), fFlags(weak_import ? BIND_SYMBOL_FLAGS_WEAK_IMPORT : 0 ), fLibraryOrdinal(ord), 
-                                                       fSymbolName(sym), fAddress(addr), fAddend(addend) {}
-                                       BindingInfo(uint8_t t, const char* sym, bool non_weak_definition, uint64_t addr, int64_t addend) 
-                                               : fType(t), fFlags(non_weak_definition ? BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION : 0 ), fLibraryOrdinal(0), 
-                                                       fSymbolName(sym), fAddress(addr), fAddend(addend) {}
-       uint8_t                 fType;
-       uint8_t                 fFlags;
-       int                             fLibraryOrdinal;
-       const char*             fSymbolName;
-       uint64_t                fAddress;
-       int64_t                 fAddend;
-       
-       // for sorting
-       int operator<(const BindingInfo& rhs) const {
-               // sort by library, symbol, type, then address
-               if ( this->fLibraryOrdinal != rhs.fLibraryOrdinal )
-                       return  (this->fLibraryOrdinal < rhs.fLibraryOrdinal );
-               if ( this->fSymbolName != rhs.fSymbolName )
-                       return ( strcmp(this->fSymbolName, rhs.fSymbolName) < 0 );
-               if ( this->fType != rhs.fType )
-                       return  (this->fType < rhs.fType );
-               return  (this->fAddress < rhs.fAddress );
-       }
-};
-
-
-class ByteStream {
-private:
-       std::vector<uint8_t>            fData;
-public:
-       std::vector<uint8_t>& bytes() { return fData; }
-       unsigned long size() const { return fData.size(); }
-       void reserve(unsigned long l) { fData.reserve(l); }
-       const uint8_t* start() const { return &fData[0]; }
-
-       void append_uleb128(uint64_t value) {
-               uint8_t byte;
-               do {
-                       byte = value & 0x7F;
-                       value &= ~0x7F;
-                       if ( value != 0 )
-                               byte |= 0x80;
-                       fData.push_back(byte);
-                       value = value >> 7;
-               } while( byte >= 0x80 );
-       }
-       
-       void append_sleb128(int64_t value) {
-               bool isNeg = ( value < 0 );
-               uint8_t byte;
-               bool more;
-               do {
-                       byte = value & 0x7F;
-                       value = value >> 7;
-                       if ( isNeg ) 
-                               more = ( (value != -1) || ((byte & 0x40) == 0) );
-                       else
-                               more = ( (value != 0) || ((byte & 0x40) != 0) );
-                       if ( more )
-                               byte |= 0x80;
-                       fData.push_back(byte);
-               } 
-               while( more );
-       }
-       
-       void append_string(const char* str) {
-               for (const char* s = str; *s != '\0'; ++s)
-                       fData.push_back(*s);
-               fData.push_back('\0');
-       }
-       
-       void append_byte(uint8_t byte) {
-               fData.push_back(byte);
-       }
-       
-       static unsigned int     uleb128_size(uint64_t value) {
-               uint32_t result = 0;
-               do {
-                       value = value >> 7;
-                       ++result;
-               } while ( value != 0 );
-               return result;
-       }
-       
-       void pad_to_size(unsigned int alignment) {
-               while ( (fData.size() % alignment) != 0 )
-                       fData.push_back(0);
-       }
-};
-
-
-template <typename A>
-class Writer : public ExecutableFile::Writer
-{
-public:
-       Writer(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries);
-       virtual                                         ~Writer();
-
-       virtual const char*                                                             getPath()                                                               { return fFilePath; }
-       virtual time_t                                                                  getModificationTime()                                   { return 0; }
-       virtual DebugInfoKind                                                   getDebugInfoKind()                                              { return ObjectFile::Reader::kDebugInfoNone; }
-       virtual std::vector<class ObjectFile::Atom*>&   getAtoms()                                                              { return fWriterSynthesizedAtoms; }
-       virtual std::vector<class ObjectFile::Atom*>*   getJustInTimeAtomsFor(const char* name) { return NULL; }
-       virtual std::vector<Stab>*                                              getStabs()                                                              { return NULL; }
-
-       virtual ObjectFile::Atom&                                               makeObjcInfoAtom(ObjectFile::Reader::ObjcConstraint objcContraint, 
-                                                                                                                                               bool objcReplacementClasses);
-       virtual class ObjectFile::Atom*                                 getUndefinedProxyAtom(const char* name);
-       virtual void                                                                    addSynthesizedAtoms(const std::vector<class ObjectFile::Atom*>& existingAtoms,
-                                                                                                                                                 class ObjectFile::Atom* dyldClassicHelperAtom,
-                                                                                                                                                 class ObjectFile::Atom* dyldCompressedHelperAtom,
-                                                                                                                                                 class ObjectFile::Atom* dyldLazyDylibHelperAtom,
-                                                                                                                                                       bool biggerThanTwoGigs,
-                                                                                                                                                       uint32_t dylibSymbolCount,
-                                                                                                                                                       std::vector<class ObjectFile::Atom*>& newAtoms);
-       virtual uint64_t                                                                write(std::vector<class ObjectFile::Atom*>& atoms,
-                                                                                                                 std::vector<class ObjectFile::Reader::Stab>& stabs,
-                                                                                                                 class ObjectFile::Atom* entryPointAtom,
-                                                                                                                 bool createUUID, bool canScatter,
-                                                                                                                 ObjectFile::Reader::CpuConstraint cpuConstraint,
-                                                                                                                 std::set<const class ObjectFile::Atom*>& atomsThatOverrideWeak,
-                                                                                                                 bool hasExternalWeakDefinitions);
-
-private:
-       typedef typename A::P                   P;
-       typedef typename A::P::uint_t   pint_t;
-
-       enum RelocKind { kRelocNone, kRelocInternal, kRelocExternal };
-
-       void                                            assignFileOffsets();
-       void                                            synthesizeStubs(const std::vector<class ObjectFile::Atom*>& existingAtoms,
-                                                                                                       std::vector<class ObjectFile::Atom*>& newAtoms);
-       void                                            synthesizeKextGOT(const std::vector<class ObjectFile::Atom*>& existingAtoms,
-                                                                       std::vector<class ObjectFile::Atom*>& newAtoms);
-       void                                            createSplitSegContent();
-       void                                            synthesizeUnwindInfoTable();
-       void                                            insertDummyStubs();
-       void                                            partitionIntoSections();
-       bool                                            addBranchIslands();
-       bool                                            createBranchIslands();
-       bool                                            isBranchThatMightNeedIsland(uint8_t kind);
-       uint32_t                                        textSizeWhenMightNeedBranchIslands();
-       uint32_t                                        maxDistanceBetweenIslands(); 
-       void                                            adjustLoadCommandsAndPadding();
-       void                                            createDynamicLinkerCommand();
-       void                                            createDylibCommands();
-       void                                            buildLinkEdit();
-       const char*                                     getArchString();
-       void                                            writeMap();
-       uint64_t                                        writeAtoms();
-       void                                            writeNoOps(int fd, uint32_t from, uint32_t to);
-       void                                            copyNoOps(uint8_t* from, uint8_t* to);
-       bool                                            segmentsCanSplitApart(const ObjectFile::Atom& from, const ObjectFile::Atom& to);
-       void                                            addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref);
-       void                                            collectExportedAndImportedAndLocalAtoms();
-       void                                            setNlistRange(std::vector<class ObjectFile::Atom*>& atoms, uint32_t startIndex, uint32_t count);
-       void                                            addLocalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name);
-       void                                            addGlobalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name);
-       void                                            buildSymbolTable();
-       bool                                            stringsNeedLabelsInObjects();
-       const char*                                     symbolTableName(const ObjectFile::Atom* atom);
-       void                                            setExportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry);
-       void                                            setImportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry);
-       void                                            setLocalNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry);
-       void                                            copyNlistRange(const std::vector<macho_nlist<P> >& entries, uint32_t startIndex);
-       uint64_t                                        getAtomLoadAddress(const ObjectFile::Atom* atom);
-       uint8_t                                         ordinalForLibrary(ObjectFile::Reader* file);
-       bool                                            targetRequiresWeakBinding(const ObjectFile::Atom& target);
-       int                                                     compressedOrdinalForImortedAtom(ObjectFile::Atom* target);
-       bool                                            shouldExport(const ObjectFile::Atom& atom) const;
-       void                                            buildFixups();
-       void                                            adjustLinkEditSections();
-       void                                            buildObjectFileFixups();
-       void                                            buildExecutableFixups();
-       bool                                            preboundLazyPointerType(uint8_t* type);
-       uint64_t                                        relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const;
-       void                                            fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const;
-       void                                            fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const;
-       void                                            fixUpReference_powerpc(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom,
-                                                                                                               uint8_t buffer[], bool finalLinkedImage) const;
-       uint32_t                                        symbolIndex(ObjectFile::Atom& atom);
-       bool                                            makesExternalRelocatableReference(ObjectFile::Atom& target) const;
-       uint32_t                                        addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref);
-       uint32_t                                        addObjectRelocs_powerpc(ObjectFile::Atom* atom, ObjectFile::Reference* ref);
-       uint8_t                                         getRelocPointerSize();
-       uint64_t                                        maxAddress();
-       bool                                            stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref);
-       bool                                            GOTReferenceKind(uint8_t kind);
-       bool                                            optimizableGOTReferenceKind(uint8_t kind);
-       bool                                            weakImportReferenceKind(uint8_t kind);
-       unsigned int                            collectStabs();
-       uint64_t                                        valueForStab(const ObjectFile::Reader::Stab& stab);
-       uint32_t                                        stringOffsetForStab(const ObjectFile::Reader::Stab& stab);
-       uint8_t                                         sectionIndexForStab(const ObjectFile::Reader::Stab& stab);
-       void                                            addStabs(uint32_t startIndex);
-       RelocKind                                       relocationNeededInFinalLinkedImage(const ObjectFile::Atom& target) const;
-       bool                                            illegalRelocInFinalLinkedImage(const ObjectFile::Reference&);
-       bool                                            generatesLocalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection);
-       bool                                            generatesExternalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection);
-       bool                                            mightNeedPadSegment();
-       void                                            scanForAbsoluteReferences();
-       bool                                            needsModuleTable();
-       void                                            optimizeDylibReferences();
-       bool                                            indirectSymbolInRelocatableIsLocal(const ObjectFile::Reference* ref) const;
-
-       struct DirectLibrary {
-               class ObjectFile::Reader*       fLibrary;
-               bool                                            fWeak;
-               bool                                            fReExport;
-       };
-
-       friend class WriterAtom<A>;
-       friend class PageZeroAtom<A>;
-       friend class CustomStackAtom<A>;
-       friend class MachHeaderAtom<A>;
-       friend class SegmentLoadCommandsAtom<A>;
-       friend class EncryptionLoadCommandsAtom<A>;
-       friend class SymbolTableLoadCommandsAtom<A>;
-       friend class DyldInfoLoadCommandsAtom<A>;
-       friend class ThreadsLoadCommandsAtom<A>;
-       friend class DylibIDLoadCommandsAtom<A>;
-       friend class RoutinesLoadCommandsAtom<A>;
-       friend class DyldLoadCommandsAtom<A>;
-       friend class UUIDLoadCommandAtom<A>;
-       friend class LinkEditAtom<A>;
-       friend class SectionRelocationsLinkEditAtom<A>;
-       friend class CompressedRebaseInfoLinkEditAtom<A>;
-       friend class CompressedBindingInfoLinkEditAtom<A>;
-       friend class CompressedWeakBindingInfoLinkEditAtom<A>;
-       friend class CompressedLazyBindingInfoLinkEditAtom<A>;
-       friend class CompressedExportInfoLinkEditAtom<A>;
-       friend class LocalRelocationsLinkEditAtom<A>;
-       friend class ExternalRelocationsLinkEditAtom<A>;
-       friend class SymbolTableLinkEditAtom<A>;
-       friend class SegmentSplitInfoLoadCommandsAtom<A>;
-       friend class SegmentSplitInfoContentAtom<A>;
-       friend class IndirectTableLinkEditAtom<A>;
-       friend class ModuleInfoLinkEditAtom<A>;
-       friend class StringsLinkEditAtom<A>;
-       friend class LoadCommandsPaddingAtom<A>;
-       friend class UnwindInfoAtom<A>;
-       friend class StubAtom<A>;
-       friend class StubHelperAtom<A>;
-       friend class ClassicStubHelperAtom<A>;
-       friend class HybridStubHelperAtom<A>;
-       friend class FastStubHelperAtom<A>;
-       friend class FastStubHelperHelperAtom<A>;
-       friend class HybridStubHelperHelperAtom<A>;
-       friend class LazyPointerAtom<A>;
-       friend class NonLazyPointerAtom<A>;
-       friend class DylibLoadCommandsAtom<A>;
-       friend class BranchIslandAtom<A>;
-
-       const char*                                                                             fFilePath;
-       Options&                                                                                fOptions;
-       std::vector<class ObjectFile::Atom*>*                   fAllAtoms;
-       std::vector<class ObjectFile::Reader::Stab>*    fStabs;
-       std::set<const class ObjectFile::Atom*>*                fRegularDefAtomsThatOverrideADylibsWeakDef;
-       class SectionInfo*                                                              fLoadCommandsSection;
-       class SegmentInfo*                                                              fLoadCommandsSegment;
-       class MachHeaderAtom<A>*                                                fMachHeaderAtom;
-       class EncryptionLoadCommandsAtom<A>*                    fEncryptionLoadCommand;
-       class SegmentLoadCommandsAtom<A>*                               fSegmentCommands;
-       class SymbolTableLoadCommandsAtom<A>*                   fSymbolTableCommands;
-       class LoadCommandsPaddingAtom<A>*                               fHeaderPadding;
-       class UnwindInfoAtom<A>*                                                fUnwindInfoAtom;
-       class UUIDLoadCommandAtom<A>*                               fUUIDAtom;
-       std::vector<class ObjectFile::Atom*>                    fWriterSynthesizedAtoms;
-       std::vector<SegmentInfo*>                                               fSegmentInfos;
-       class SegmentInfo*                                                              fPadSegmentInfo;
-       class ObjectFile::Atom*                                                 fEntryPoint;
-       class ObjectFile::Atom*                                                 fDyldClassicHelperAtom;
-       class ObjectFile::Atom*                                                 fDyldCompressedHelperAtom;
-       class ObjectFile::Atom*                                                 fDyldLazyDylibHelper;
-       std::map<class ObjectFile::Reader*, DylibLoadCommandsAtom<A>*>  fLibraryToLoadCommand;
-       std::map<class ObjectFile::Reader*, uint32_t>   fLibraryToOrdinal;
-       std::map<class ObjectFile::Reader*, class ObjectFile::Reader*>  fLibraryAliases;
-       std::set<class ObjectFile::Reader*>                             fForcedWeakImportReaders;
-       std::vector<class ObjectFile::Atom*>                    fExportedAtoms;
-       std::vector<class ObjectFile::Atom*>                    fImportedAtoms;
-       std::vector<class ObjectFile::Atom*>                    fLocalSymbolAtoms;
-       std::vector<macho_nlist<P> >                                    fLocalExtraLabels;
-       std::vector<macho_nlist<P> >                                    fGlobalExtraLabels;
-       std::map<ObjectFile::Atom*, uint32_t>                   fAtomToSymbolIndex;
-       class SectionRelocationsLinkEditAtom<A>*                fSectionRelocationsAtom;        
-       class CompressedRebaseInfoLinkEditAtom<A>*              fCompressedRebaseInfoAtom;
-       class CompressedBindingInfoLinkEditAtom<A>*             fCompressedBindingInfoAtom;
-       class CompressedWeakBindingInfoLinkEditAtom<A>* fCompressedWeakBindingInfoAtom;
-       class CompressedLazyBindingInfoLinkEditAtom<A>* fCompressedLazyBindingInfoAtom;
-       class CompressedExportInfoLinkEditAtom<A>*              fCompressedExportInfoAtom;
-       class LocalRelocationsLinkEditAtom<A>*                  fLocalRelocationsAtom;
-       class ExternalRelocationsLinkEditAtom<A>*               fExternalRelocationsAtom;
-       class SymbolTableLinkEditAtom<A>*                               fSymbolTableAtom;
-       class SegmentSplitInfoContentAtom<A>*                   fSplitCodeToDataContentAtom;
-       class IndirectTableLinkEditAtom<A>*                             fIndirectTableAtom;
-       class ModuleInfoLinkEditAtom<A>*                                fModuleInfoAtom;
-       class StringsLinkEditAtom<A>*                                   fStringsAtom;
-       class PageZeroAtom<A>*                                                  fPageZeroAtom;
-       class NonLazyPointerAtom<A>*                                    fFastStubGOTAtom;
-       macho_nlist<P>*                                                                 fSymbolTable;
-       std::vector<macho_relocation_info<P> >                  fSectionRelocs;
-       std::vector<macho_relocation_info<P> >                  fInternalRelocs;
-       std::vector<macho_relocation_info<P> >                  fExternalRelocs;
-       std::vector<RebaseInfo>                                                 fRebaseInfo;
-       std::vector<BindingInfo>                                                fBindingInfo;
-       std::vector<BindingInfo>                                                fWeakBindingInfo;
-       std::map<const ObjectFile::Atom*,ObjectFile::Atom*>     fStubsMap;
-       std::map<ObjectFile::Atom*,ObjectFile::Atom*>   fGOTMap;
-       std::vector<class StubAtom<A>*>                                 fAllSynthesizedStubs;
-       std::vector<ObjectFile::Atom*>                                  fAllSynthesizedStubHelpers;
-       std::vector<class LazyPointerAtom<A>*>                  fAllSynthesizedLazyPointers;
-       std::vector<class LazyPointerAtom<A>*>                  fAllSynthesizedLazyDylibPointers;
-       std::vector<class NonLazyPointerAtom<A>*>               fAllSynthesizedNonLazyPointers;
-       uint32_t                                                                                fSymbolTableCount;
-       uint32_t                                                                                fSymbolTableStabsCount;
-       uint32_t                                                                                fSymbolTableStabsStartIndex;
-       uint32_t                                                                                fSymbolTableLocalCount;
-       uint32_t                                                                                fSymbolTableLocalStartIndex;
-       uint32_t                                                                                fSymbolTableExportCount;
-       uint32_t                                                                                fSymbolTableExportStartIndex;
-       uint32_t                                                                                fSymbolTableImportCount;
-       uint32_t                                                                                fSymbolTableImportStartIndex;
-       uint32_t                                                                                fLargestAtomSize;
-       uint32_t                                                                                fDylibSymbolCountUpperBound;
-       bool                                                                                    fEmitVirtualSections;
-       bool                                                                                    fHasWeakExports;
-       bool                                                                                    fReferencesWeakImports;
-       bool                                                                                    fCanScatter;
-       bool                                                                                    fWritableSegmentPastFirst4GB;
-       bool                                                                                    fNoReExportedDylibs;
-       bool                                                                                    fBiggerThanTwoGigs;
-       bool                                                                                    fSlideable;
-       bool                                                                                    fHasThumbBranches;
-       std::map<const ObjectFile::Atom*,bool>                  fWeakImportMap;
-       std::set<const ObjectFile::Reader*>                             fDylibReadersWithNonWeakImports;
-       std::set<const ObjectFile::Reader*>                             fDylibReadersWithWeakImports;
-       SegmentInfo*                                                                    fFirstWritableSegment;
-       ObjectFile::Reader::CpuConstraint                               fCpuConstraint;
-       uint32_t                                                                                fAnonNameIndex;
-};
-
-
-class Segment : public ObjectFile::Segment
-{
-public:
-                                                               Segment(const char* name, bool readable, bool writable, bool executable, bool fixedAddress)
-                                                                                        : fName(name), fReadable(readable), fWritable(writable), fExecutable(executable), fFixedAddress(fixedAddress) {}
-       virtual const char*                     getName() const                                 { return fName; }
-       virtual bool                            isContentReadable() const               { return fReadable; }
-       virtual bool                            isContentWritable() const               { return fWritable; }
-       virtual bool                            isContentExecutable() const             { return fExecutable; }
-       virtual bool                            hasFixedAddress() const                 { return fFixedAddress; }
-       
-       static Segment                                                          fgTextSegment;
-       static Segment                                                          fgPageZeroSegment;
-       static Segment                                                          fgLinkEditSegment;
-       static Segment                                                          fgStackSegment;
-       static Segment                                                          fgImportSegment;
-       static Segment                                                          fgROImportSegment;
-       static Segment                                                          fgDataSegment;
-       static Segment                                                          fgObjCSegment;
-       static Segment                                                          fgHeaderSegment;
-       
-       
-private:
-       const char*                                     fName;
-       const bool                                      fReadable;
-       const bool                                      fWritable;
-       const bool                                      fExecutable;
-       const bool                                      fFixedAddress;
-};
-
-Segment                Segment::fgPageZeroSegment("__PAGEZERO", false, false, false, true);
-Segment                Segment::fgTextSegment("__TEXT", true, false, true, false);
-Segment                Segment::fgLinkEditSegment("__LINKEDIT", true, false, false, false);
-Segment                Segment::fgStackSegment("__UNIXSTACK", true, true, false, true);
-Segment                Segment::fgImportSegment("__IMPORT", true, true, true, false);
-Segment                Segment::fgROImportSegment("__IMPORT", true, false, true, false);
-Segment                Segment::fgDataSegment("__DATA", true, true, false, false);
-Segment                Segment::fgObjCSegment("__OBJC", true, true, false, false);
-Segment                Segment::fgHeaderSegment("__HEADER", true, false, true, false);
-
-
-template <typename A>
-class WriterAtom : public ObjectFile::Atom
-{
-public:
-       enum Kind { zeropage, machHeaderApp, machHeaderDylib, machHeaderBundle, machHeaderObject, loadCommands, undefinedProxy };
-                                                                                       WriterAtom(Writer<A>& writer, Segment& segment) : fWriter(writer), fSegment(segment) { }
-
-       virtual ObjectFile::Reader*                             getFile() const                                 { return &fWriter; }
-       virtual bool                                                    getTranslationUnitSource(const char** dir, const char** name) const { return false; }
-       virtual const char*                                             getName() const                                 { return NULL; }
-       virtual const char*                                             getDisplayName() const                  { return this->getName(); }
-       virtual Scope                                                   getScope() const                                { return ObjectFile::Atom::scopeTranslationUnit; }
-       virtual DefinitionKind                                  getDefinitionKind() const               { return kRegularDefinition; }
-       virtual SymbolTableInclusion                    getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
-       virtual bool                                                    dontDeadStrip() const                   { return true; }
-       virtual bool                                                    isZeroFill() const                              { return false; }
-       virtual bool                                                    isThumb() const                                 { return false; }
-       virtual std::vector<ObjectFile::Reference*>&  getReferences() const             { return fgEmptyReferenceList; }
-       virtual bool                                                    mustRemainInSection() const             { return true; }
-       virtual ObjectFile::Segment&                    getSegment() const                              { return fSegment; }
-       virtual ObjectFile::Atom&                               getFollowOnAtom() const                 { return *((ObjectFile::Atom*)NULL); }
-       virtual uint32_t                                                getOrdinal() const                              { return 0; }
-       virtual std::vector<ObjectFile::LineInfo>*      getLineInfo() const                     { return NULL; }
-       virtual ObjectFile::Alignment                   getAlignment() const                    { return ObjectFile::Alignment(2); }
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const { throw "don't use copyRawContent"; }
-       virtual void                                                    setScope(Scope)                                 { }
-
-
-protected:
-       virtual                                                                 ~WriterAtom() {}
-       typedef typename A::P                                   P;
-       typedef typename A::P::E                                E;
-
-       static Segment&                 headerSegment(Writer<A>& writer) { return (writer.fOptions.outputKind()==Options::kPreload)
-                                                                                                                                       ? Segment::fgHeaderSegment : Segment::fgTextSegment; }
-
-       static std::vector<ObjectFile::Reference*>      fgEmptyReferenceList;
-
-       Writer<A>&                                                                      fWriter;
-       Segment&                                                                        fSegment;
-};
-
-template <typename A> std::vector<ObjectFile::Reference*>      WriterAtom<A>::fgEmptyReferenceList;
-
-
-template <typename A>
-class PageZeroAtom : public WriterAtom<A>
-{
-public:
-                                                                                       PageZeroAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgPageZeroSegment),
-                                                                                                                                                       fSize(fWriter.fOptions.zeroPageSize()) {}
-       virtual const char*                                             getDisplayName() const  { return "page zero content"; }
-       virtual bool                                                    isZeroFill() const              { return true; }
-       virtual uint64_t                                                getSize() const                 { return fSize; }
-       virtual const char*                                             getSectionName() const  { return "._zeropage"; }
-       virtual ObjectFile::Alignment                   getAlignment() const    { return ObjectFile::Alignment(12); }
-       void                                                                    setSize(uint64_t size)  { fSize = size; }
-private:
-       using WriterAtom<A>::fWriter;
-       typedef typename A::P                                   P;
-       uint64_t                                                                fSize;
-};
-
-
-template <typename A>
-class DsoHandleAtom : public WriterAtom<A>
-{
-public:
-                                                                                                       DsoHandleAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgTextSegment) {}
-       virtual const char*                                                             getName() const                         { return "___dso_handle"; }
-       virtual ObjectFile::Atom::Scope                                 getScope() const                        { return ObjectFile::Atom::scopeLinkageUnit; }
-       virtual ObjectFile::Atom::SymbolTableInclusion  getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
-       virtual uint64_t                                                                getSize() const                         { return 0; }
-       virtual ObjectFile::Alignment                                   getAlignment() const            { return ObjectFile::Alignment(12); }
-       virtual const char*                                                             getSectionName() const          { return "._mach_header"; }
-       virtual void                                                                    copyRawContent(uint8_t buffer[]) const {}
-};
-
-
-template <typename A>
-class MachHeaderAtom : public WriterAtom<A>
-{
-public:
-                                                                                                       MachHeaderAtom(Writer<A>& writer) : WriterAtom<A>(writer, headerSegment(writer)) {}
-       virtual const char*                                                             getName() const;
-       virtual const char*                                                             getDisplayName() const;
-       virtual ObjectFile::Atom::Scope                                 getScope() const;
-       virtual ObjectFile::Atom::SymbolTableInclusion  getSymbolTableInclusion() const;
-       virtual uint64_t                                                                getSize() const                         { return sizeof(macho_header<typename A::P>); }
-       virtual ObjectFile::Alignment                                   getAlignment() const            { return ObjectFile::Alignment(12); }
-       virtual const char*                                                             getSectionName() const          { return "._mach_header"; }
-       virtual uint32_t                                                                getOrdinal() const                      { return 1; }
-       virtual void                                                                    copyRawContent(uint8_t buffer[]) const;
-private:
-       using WriterAtom<A>::fWriter;
-       typedef typename A::P                                   P;
-       void                                                                    setHeaderInfo(macho_header<typename A::P>& header) const;
-};
-
-template <typename A>
-class CustomStackAtom : public WriterAtom<A>
-{
-public:
-                                                                                       CustomStackAtom(Writer<A>& writer);
-       virtual const char*                                             getDisplayName() const  { return "custom stack content"; }
-       virtual bool                                                    isZeroFill() const              { return true; }
-       virtual uint64_t                                                getSize() const                 { return fWriter.fOptions.customStackSize(); }
-       virtual const char*                                             getSectionName() const  { return "._stack"; }
-       virtual ObjectFile::Alignment                   getAlignment() const    { return ObjectFile::Alignment(12); }
-private:
-       using WriterAtom<A>::fWriter;
-       typedef typename A::P                                   P;
-       static bool                                                             stackGrowsDown();
-};
-
-template <typename A>
-class LoadCommandAtom : public WriterAtom<A>
-{
-protected:
-                                                                                       LoadCommandAtom(Writer<A>& writer) : WriterAtom<A>(writer, headerSegment(writer)), fOrdinal(fgCurrentOrdinal++) {}
-       virtual ObjectFile::Alignment                   getAlignment() const    { return ObjectFile::Alignment(log2(sizeof(typename A::P::uint_t))); }
-       virtual const char*                                             getSectionName() const  { return "._load_commands"; }
-       virtual uint32_t                                                getOrdinal() const              { return fOrdinal; }
-       static uint64_t                                                 alignedSize(uint64_t size);
-protected:
-       uint32_t                                                                fOrdinal;
-       static uint32_t                                                 fgCurrentOrdinal;
-};
-
-template <typename A> uint32_t LoadCommandAtom<A>::fgCurrentOrdinal = 0;
-
-template <typename A>
-class SegmentLoadCommandsAtom : public LoadCommandAtom<A>
-{
-public:
-                                                                                       SegmentLoadCommandsAtom(Writer<A>& writer)  
-                                                                                               : LoadCommandAtom<A>(writer), fCommandCount(0), fSize(0) 
-                                                                                               { writer.fSegmentCommands = this; }
-       virtual const char*                                             getDisplayName() const  { return "segment load commands"; }
-       virtual uint64_t                                                getSize() const                 { return fSize; }
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
-
-       void                                                                    computeSize();
-       void                                                                    setup();
-       unsigned int                                                    commandCount()                  { return fCommandCount; }
-private:
-       using WriterAtom<A>::fWriter;
-       typedef typename A::P                                   P;
-       unsigned int                                                    fCommandCount;
-       uint32_t                                                                fSize;
-};
-
-
-template <typename A>
-class SymbolTableLoadCommandsAtom : public LoadCommandAtom<A>
-{
-public:
-                                                                                       SymbolTableLoadCommandsAtom(Writer<A>&);
-       virtual const char*                                             getDisplayName() const { return "symbol table load commands"; }
-       virtual uint64_t                                                getSize() const;
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
-       unsigned int                                                    commandCount();
-                       void                                                    needDynamicTable();
-private:
-       using WriterAtom<A>::fWriter;
-       typedef typename A::P                                   P;
-       bool                                                                    fNeedsDynamicSymbolTable;
-       macho_symtab_command<typename A::P>             fSymbolTable;
-       macho_dysymtab_command<typename A::P>   fDynamicSymbolTable;
-};
-
-template <typename A>
-class ThreadsLoadCommandsAtom : public LoadCommandAtom<A>
-{
-public:
-                                                                                       ThreadsLoadCommandsAtom(Writer<A>& writer) 
-                                                                                               : LoadCommandAtom<A>(writer) {}
-       virtual const char*                                             getDisplayName() const { return "thread load commands"; }
-       virtual uint64_t                                                getSize() const;
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
-private:
-       using WriterAtom<A>::fWriter;
-       typedef typename A::P                                   P;
-       uint8_t*                                                                fBuffer;
-       uint32_t                                                                fBufferSize;
-};
-
-template <typename A>
-class DyldLoadCommandsAtom : public LoadCommandAtom<A>
-{
-public:
-                                                                                       DyldLoadCommandsAtom(Writer<A>& writer)  : LoadCommandAtom<A>(writer) {}
-       virtual const char*                                             getDisplayName() const  { return "dyld load command"; }
-       virtual uint64_t                                                getSize() const;
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
-private:
-       using WriterAtom<A>::fWriter;
-       typedef typename A::P                                   P;
-};
-
-template <typename A>
-class SegmentSplitInfoLoadCommandsAtom : public LoadCommandAtom<A>
-{
-public:
-                                                                                       SegmentSplitInfoLoadCommandsAtom(Writer<A>& writer)  : LoadCommandAtom<A>(writer) {}
-       virtual const char*                                             getDisplayName() const  { return "segment split info load command"; }
-       virtual uint64_t                                                getSize() const;
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
-private:
-       using WriterAtom<A>::fWriter;
-       typedef typename A::P                                   P;
-};
-
-template <typename A>
-class AllowableClientLoadCommandsAtom : public LoadCommandAtom<A>
-{
-public:
-       AllowableClientLoadCommandsAtom(Writer<A>& writer, const char* client)  :
-               LoadCommandAtom<A>(writer), clientString(client) {}
-       virtual const char*                                                     getDisplayName() const  { return "allowable_client load command"; }
-       virtual uint64_t                                                        getSize() const;
-       virtual void                                                            copyRawContent(uint8_t buffer[]) const;
-private:
-       using WriterAtom<A>::fWriter;
-       typedef typename A::P                                           P;
-       const char*                                                                     clientString;
-};
-
-template <typename A>
-class DylibLoadCommandsAtom : public LoadCommandAtom<A>
-{
-public:
-                                                                                       DylibLoadCommandsAtom(Writer<A>& writer, ExecutableFile::DyLibUsed& info) 
-                                                                                        : LoadCommandAtom<A>(writer), fInfo(info), 
-                                                                                               fOptimizedAway(false) { if (fInfo.options.fLazyLoad) this->fOrdinal += 256; }
-       virtual const char*                                             getDisplayName() const  { return "dylib load command"; }
-       virtual uint64_t                                                getSize() const;
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
-       virtual void                                                    optimizeAway() { fOptimizedAway = true; }
-                       bool                                                    linkedWeak() { return fInfo.options.fWeakImport; }
-private:
-       using WriterAtom<A>::fWriter;
-       typedef typename A::P                                   P;
-       ExecutableFile::DyLibUsed                               fInfo;
-       bool                                                                    fOptimizedAway;
-};
-
-template <typename A>
-class DylibIDLoadCommandsAtom : public LoadCommandAtom<A>
-{
-public:
-                                                                                       DylibIDLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer) {}
-       virtual const char*                                             getDisplayName() const { return "dylib ID load command"; }
-       virtual uint64_t                                                getSize() const;
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
-private:
-       using WriterAtom<A>::fWriter;
-       typedef typename A::P                                   P;
-};
-
-template <typename A>
-class RoutinesLoadCommandsAtom : public LoadCommandAtom<A>
-{
-public:
-                                                                                       RoutinesLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer) {}
-       virtual const char*                                             getDisplayName() const { return "routines load command"; }
-       virtual uint64_t                                                getSize() const                 { return sizeof(macho_routines_command<typename A::P>); }
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
-private:
-       using WriterAtom<A>::fWriter;
-       typedef typename A::P                                   P;
-};
-
-template <typename A>
-class SubUmbrellaLoadCommandsAtom : public LoadCommandAtom<A>
-{
-public:
-                                                                                       SubUmbrellaLoadCommandsAtom(Writer<A>& writer, const char* name) 
-                                                                                        : LoadCommandAtom<A>(writer), fName(name) {}
-       virtual const char*                                             getDisplayName() const  { return "sub-umbrella load command"; }
-       virtual uint64_t                                                getSize() const;
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
-private:
-       typedef typename A::P                                   P;
-       const char*                                                             fName;
-};
-
-template <typename A>
-class SubLibraryLoadCommandsAtom : public LoadCommandAtom<A>
-{
-public:
-                                                                                       SubLibraryLoadCommandsAtom(Writer<A>& writer,  const char* nameStart, int nameLen)
-                                                                                               : LoadCommandAtom<A>(writer), fNameStart(nameStart), fNameLength(nameLen) {}
-       virtual const char*                                             getDisplayName() const  { return "sub-library load command"; }
-       virtual uint64_t                                                getSize() const;
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
-private:
-       using WriterAtom<A>::fWriter;
-       typedef typename A::P                                   P;
-       const char*                                                             fNameStart;
-       int                                                                             fNameLength;
-};
-
-template <typename A>
-class UmbrellaLoadCommandsAtom : public LoadCommandAtom<A>
-{
-public:
-                                                                                       UmbrellaLoadCommandsAtom(Writer<A>& writer, const char* name)
-                                                                                                       : LoadCommandAtom<A>(writer), fName(name) {}
-       virtual const char*                                             getDisplayName() const  { return "umbrella load command"; }
-       virtual uint64_t                                                getSize() const;
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
-private:
-       using WriterAtom<A>::fWriter;
-       typedef typename A::P                                   P;
-       const char*                                                             fName;
-};
-
-template <typename A>
-class UUIDLoadCommandAtom : public LoadCommandAtom<A>
-{
-public:
-                                                                                       UUIDLoadCommandAtom(Writer<A>& writer)
-                                                                                               : LoadCommandAtom<A>(writer), fEmit(false) {}
-       virtual const char*                                             getDisplayName() const  { return "uuid load command"; }
-       virtual uint64_t                                                getSize() const                 { return fEmit ? sizeof(macho_uuid_command<typename A::P>) : 0; }
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
-       virtual void                                                generate();
-                       void                                                setContent(const uint8_t uuid[16]);
-                       const uint8_t*                                  getUUID()                               { return fUUID; }
-private:
-       using WriterAtom<A>::fWriter;
-       typedef typename A::P                                   P;
-       uuid_t                                                                  fUUID;
-       bool                                                                fEmit;
-};
-
-
-template <typename A>
-class RPathLoadCommandsAtom : public LoadCommandAtom<A>
-{
-public:
-                                                                                       RPathLoadCommandsAtom(Writer<A>& writer, const char* path)
-                                                                                               : LoadCommandAtom<A>(writer), fPath(path) {}
-       virtual const char*                                             getDisplayName() const  { return "rpath load command"; }
-       virtual uint64_t                                                getSize() const;
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
-private:
-       using WriterAtom<A>::fWriter;
-       typedef typename A::P                                   P;
-       const char*                                                             fPath;
-};
-
-template <typename A>
-class EncryptionLoadCommandsAtom : public LoadCommandAtom<A>
-{
-public:
-                                                                                       EncryptionLoadCommandsAtom(Writer<A>& writer)
-                                                                                               : LoadCommandAtom<A>(writer), fStartOffset(0),
-                                                                                                 fEndOffset(0) {}
-       virtual const char*                                             getDisplayName() const  { return "encryption info load command"; }
-       virtual uint64_t                                                getSize() const { return sizeof(macho_encryption_info_command<typename A::P>); }
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
-       void                                                                    setStartEncryptionOffset(uint32_t off) { fStartOffset = off; }
-       void                                                                    setEndEncryptionOffset(uint32_t off) { fEndOffset = off; }
-private:
-       using WriterAtom<A>::fWriter;
-       typedef typename A::P                                   P;
-       uint32_t                                                                fStartOffset;
-       uint32_t                                                                fEndOffset;
-};
-
-template <typename A>
-class DyldInfoLoadCommandsAtom : public LoadCommandAtom<A>
-{
-public:
-                                                                                       DyldInfoLoadCommandsAtom(Writer<A>& writer)
-                                                                                               : LoadCommandAtom<A>(writer) {}
-       virtual const char*                                             getDisplayName() const  { return "dyld info load command"; }
-       virtual uint64_t                                                getSize() const { return sizeof(macho_dyld_info_command<typename A::P>); }
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
-private:
-       using WriterAtom<A>::fWriter;
-       typedef typename A::P                                   P;
-};
-
-
-template <typename A>
-class LoadCommandsPaddingAtom : public WriterAtom<A>
-{
-public:
-                                                                                       LoadCommandsPaddingAtom(Writer<A>& writer)
-                                                                                                       : WriterAtom<A>(writer, headerSegment(writer)), fSize(0) {}
-       virtual const char*                                             getDisplayName() const  { return "header padding"; }
-       virtual uint64_t                                                getSize() const                 { return fSize; }
-       virtual const char*                                             getSectionName() const  { return "._load_cmds_pad"; }
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
-
-       void                                                                    setSize(uint64_t newSize);
-private:
-       using WriterAtom<A>::fWriter;
-       typedef typename A::P                                   P;
-       uint64_t                                                                fSize;
-};
-
-template <typename A>
-class MinimalTextAtom : public WriterAtom<A>
-{
-public:
-                                                                                       MinimalTextAtom(Writer<A>& writer)
-                                                                                                       : WriterAtom<A>(writer, headerSegment(writer)) {}
-       virtual const char*                                             getDisplayName() const  { return "minimal text"; }
-       virtual uint64_t                                                getSize() const                 { return 0; }
-       virtual const char*                                             getSectionName() const  { return "__text"; }
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const { }
-       virtual ObjectFile::Atom::SymbolTableInclusion  getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
-       
-private:
-       using WriterAtom<A>::fWriter;
-};
-
-
-template <typename A>
-class UnwindInfoAtom : public WriterAtom<A>
-{
-public:
-                                                                                                       UnwindInfoAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgTextSegment), 
-                                                                                                                                                                               fHeaderSize(0), fPagesSize(0), fAlignment(4) {}
-       virtual const char*                                                             getName() const                         { return "unwind info"; }
-       virtual ObjectFile::Atom::Scope                                 getScope() const                        { return ObjectFile::Atom::scopeTranslationUnit; }
-       virtual ObjectFile::Atom::SymbolTableInclusion  getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
-       virtual uint64_t                                                                getSize() const                         { return fHeaderSize+fPagesSize; }
-       virtual ObjectFile::Alignment                                   getAlignment() const            { return fAlignment; }
-       virtual const char*                                                             getSectionName() const          { return "__unwind_info"; }
-       virtual uint32_t                                                                getOrdinal() const                      { return 1; }
-       virtual std::vector<ObjectFile::Reference*>&    getReferences() const           { return (std::vector<ObjectFile::Reference*>&)fReferences; }
-       virtual void                                                                    copyRawContent(uint8_t buffer[]) const;
-
-       void                                                                                    addUnwindInfo(ObjectFile::Atom* func, uint32_t offset, uint32_t encoding, 
-                                                                                                                       ObjectFile::Reference* fdeRef, ObjectFile::Reference* lsda,
-                                                                                                                        ObjectFile::Atom* personalityPointer);
-       void                                                                                    generate();
-       
-private:
-       using WriterAtom<A>::fWriter;
-       typedef typename A::P                                   P;
-       struct Info { ObjectFile::Atom* func; ObjectFile::Atom* fde; ObjectFile::Atom* lsda; uint32_t lsdaOffset; ObjectFile::Atom* personalityPointer; uint32_t encoding; };
-       struct LSDAEntry { ObjectFile::Atom* func; ObjectFile::Atom* lsda; uint32_t lsdaOffset; };
-       struct RegFixUp { uint8_t* contentPointer; ObjectFile::Atom* func; ObjectFile::Atom* fde; };
-       struct CompressedFixUp { uint8_t* contentPointer; ObjectFile::Atom* func; ObjectFile::Atom* fromFunc; };
-       struct CompressedEncodingFixUp { uint8_t* contentPointer; ObjectFile::Atom* fde; };
-
-       bool                            encodingMeansUseDwarf(compact_unwind_encoding_t encoding);
-       void                            compressDuplicates(std::vector<Info>& uniqueInfos);
-       void                            findCommonEncoding(const std::vector<Info>& uniqueInfos, std::map<uint32_t, unsigned int>& commonEncodings);
-       void                            makeLsdaIndex(const std::vector<Info>& uniqueInfos, std::map<ObjectFile::Atom*, uint32_t>& lsdaIndexOffsetMap);
-       unsigned int            makeRegularSecondLevelPage(const std::vector<Info>& uniqueInfos, uint32_t pageSize, unsigned int endIndex, 
-                                                                                                       uint8_t*& pageEnd);
-       unsigned int            makeCompressedSecondLevelPage(const std::vector<Info>& uniqueInfos,   
-                                                                                                               const std::map<uint32_t,unsigned int> commonEncodings,  
-                                                                                                               uint32_t pageSize, unsigned int endIndex, uint8_t*& pageEnd);
-       void                            makePersonalityIndex(std::vector<Info>& uniqueInfos);
-       
-
-       uint32_t                                                                fHeaderSize;
-       uint32_t                                                                fPagesSize;
-       uint8_t*                                                                fHeaderContent;
-       uint8_t*                                                                fPagesContent;
-       uint8_t*                                                                fPagesContentForDelete;
-       ObjectFile::Alignment                                   fAlignment;
-       std::vector<Info>                                               fInfos;
-       std::map<ObjectFile::Atom*, uint32_t>   fPersonalityIndexMap;
-       std::vector<LSDAEntry>                                  fLSDAIndex;
-       std::vector<RegFixUp>                                   fRegFixUps;
-       std::vector<CompressedFixUp>                    fCompressedFixUps;
-       std::vector<CompressedEncodingFixUp>    fCompressedEncodingFixUps;
-       std::vector<ObjectFile::Reference*>             fReferences;
-};
-
-
-
-template <typename A>
-class LinkEditAtom : public WriterAtom<A>
-{
-public:
-                                                                                       LinkEditAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgLinkEditSegment), fOrdinal(fgCurrentOrdinal++) {}
-       uint64_t                                                                getFileOffset() const;
-       virtual ObjectFile::Alignment                   getAlignment() const    { return ObjectFile::Alignment(log2(sizeof(typename A::P::uint_t))); }
-       virtual uint32_t                                                getOrdinal() const              { return fOrdinal; }
-private:
-       uint32_t                                                                fOrdinal;
-       static uint32_t                                                 fgCurrentOrdinal;
-private:
-       typedef typename A::P                                   P;
-};
-
-template <typename A> uint32_t LinkEditAtom<A>::fgCurrentOrdinal = 0;
-
-template <typename A>
-class SectionRelocationsLinkEditAtom : public LinkEditAtom<A>
-{
-public:
-                                                                                       SectionRelocationsLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
-       virtual const char*                                             getDisplayName() const  { return "section relocations"; }
-       virtual uint64_t                                                getSize() const;
-       virtual const char*                                             getSectionName() const  { return "._section_relocs"; }
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
-private:
-       using WriterAtom<A>::fWriter;
-       typedef typename A::P                                   P;
-};
-
-template <typename A>
-class CompressedInfoLinkEditAtom : public LinkEditAtom<A>
-{
-public:
-                                                                                       CompressedInfoLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
-       virtual uint64_t                                                getSize() const { return fEncodedData.size(); }
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const { memcpy(buffer, fEncodedData.start(), fEncodedData.size()); }
-protected:
-       typedef typename A::P::uint_t                   pint_t;
-       ByteStream                                                              fEncodedData;
-private:
-       using WriterAtom<A>::fWriter;
-       typedef typename A::P                                   P;
-};
-
-
-
-template <typename A>
-class CompressedRebaseInfoLinkEditAtom : public CompressedInfoLinkEditAtom<A>
-{
-public:
-                                                                                       CompressedRebaseInfoLinkEditAtom(Writer<A>& writer) : CompressedInfoLinkEditAtom<A>(writer) { }
-       virtual const char*                                             getDisplayName() const  { return "compressed rebase info"; }
-       virtual const char*                                             getSectionName() const  { return "._rebase info"; }
-       void                                                                    encode();
-private:
-       using CompressedInfoLinkEditAtom<A>::fEncodedData;
-       using CompressedInfoLinkEditAtom<A>::fWriter;
-       typedef typename A::P                                   P;
-       typedef typename A::P::uint_t                   pint_t;
-};
-
-template <typename A>
-class CompressedBindingInfoLinkEditAtom : public CompressedInfoLinkEditAtom<A>
-{
-public:
-                                                                                       CompressedBindingInfoLinkEditAtom(Writer<A>& writer) : CompressedInfoLinkEditAtom<A>(writer) { }
-       virtual const char*                                             getDisplayName() const  { return "compressed binding info"; }
-       virtual const char*                                             getSectionName() const  { return "._binding info"; }
-       void                                                                    encode();
-private:
-       using CompressedInfoLinkEditAtom<A>::fWriter;
-       using CompressedInfoLinkEditAtom<A>::fEncodedData;
-       typedef typename A::P                                   P;
-       typedef typename A::P::uint_t                   pint_t;
-};
-
-template <typename A>
-class CompressedWeakBindingInfoLinkEditAtom : public CompressedInfoLinkEditAtom<A>
-{
-public:
-                                                                                       CompressedWeakBindingInfoLinkEditAtom(Writer<A>& writer) : CompressedInfoLinkEditAtom<A>(writer) { }
-       virtual const char*                                             getDisplayName() const  { return "compressed weak binding info"; }
-       virtual const char*                                             getSectionName() const  { return "._wkbinding info"; }
-       void                                                                    encode();
-private:
-       using CompressedInfoLinkEditAtom<A>::fWriter;
-       using CompressedInfoLinkEditAtom<A>::fEncodedData;
-       typedef typename A::P                                   P;
-       typedef typename A::P::uint_t                   pint_t;
-};
-
-template <typename A>
-class CompressedLazyBindingInfoLinkEditAtom : public CompressedInfoLinkEditAtom<A>
-{
-public:
-                                                                                       CompressedLazyBindingInfoLinkEditAtom(Writer<A>& writer) : CompressedInfoLinkEditAtom<A>(writer) { }
-       virtual const char*                                             getDisplayName() const  { return "compressed lazy binding info"; }
-       virtual const char*                                             getSectionName() const  { return "._lzbinding info"; }
-       void                                                                    encode();
-private:
-       std::vector<uint32_t>                                   fStarts;
-       
-       using CompressedInfoLinkEditAtom<A>::fWriter;
-       using CompressedInfoLinkEditAtom<A>::fEncodedData;
-       typedef typename A::P                                   P;
-       typedef typename A::P::uint_t                   pint_t;
-};
-
-
-template <typename A>
-class CompressedExportInfoLinkEditAtom : public CompressedInfoLinkEditAtom<A>
-{
-public:
-                                                                                       CompressedExportInfoLinkEditAtom(Writer<A>& writer) 
-                                                                                       : CompressedInfoLinkEditAtom<A>(writer), fStartNode(strdup("")) { }
-       virtual const char*                                             getDisplayName() const  { return "compressed export info"; }
-       virtual const char*                                             getSectionName() const  { return "._export info"; }
-       void                                                                    encode();
-private:
-       using WriterAtom<A>::fWriter;
-       using CompressedInfoLinkEditAtom<A>::fEncodedData;
-       typedef typename A::P                                   P;
-       typedef typename A::P::uint_t                   pint_t;
-       struct node;
-       
-       struct edge
-       {
-                                               edge(const char* s, struct node* n) : fSubString(s), fChild(n) { }
-                                               ~edge() {  }
-               const char*             fSubString;
-               struct node*    fChild;
-               
-       };
-
-       struct node
-       {
-                                                       node(const char* s) : fCummulativeString(s), fAddress(0), fFlags(0), fOrdered(false), 
-                                                                                               fHaveExportInfo(false), fTrieOffset(0) {}
-                                                       ~node() { }
-               const char*                     fCummulativeString;
-               std::vector<edge>       fChildren;
-               uint64_t                        fAddress;
-               uint32_t                        fFlags;
-               bool                            fOrdered;
-               bool                            fHaveExportInfo;
-               uint32_t                        fTrieOffset;
-               
-               void addSymbol(const char* fullStr, uint64_t address, uint32_t flags) {
-                       const char* partialStr = &fullStr[strlen(fCummulativeString)];
-                       for (typename std::vector<edge>::iterator it = fChildren.begin(); it != fChildren.end(); ++it) {
-                               edge& e = *it;
-                               int subStringLen = strlen(e.fSubString);
-                               if ( strncmp(e.fSubString, partialStr, subStringLen) == 0 ) {
-                                       // already have matching edge, go down that path
-                                       e.fChild->addSymbol(fullStr, address, flags);
-                                       return;
-                               }
-                               else {
-                                       for (int i=subStringLen-1; i > 0; --i) {
-                                               if ( strncmp(e.fSubString, partialStr, i) == 0 ) {
-                                                       // found a common substring, splice in new node
-                                                       //  was A -> C,  now A -> B -> C
-                                                       char* bNodeCummStr = strdup(e.fChild->fCummulativeString);
-                                                       bNodeCummStr[strlen(bNodeCummStr)+i-subStringLen] = '\0';
-                                                       //node* aNode = this;
-                                                       node* bNode = new node(bNodeCummStr);
-                                                       node* cNode = e.fChild;
-                                                       char* abEdgeStr = strdup(e.fSubString);
-                                                       abEdgeStr[i] = '\0';
-                                                       char* bcEdgeStr = strdup(&e.fSubString[i]);
-                                                       edge& abEdge = e;
-                                                       abEdge.fSubString = abEdgeStr;
-                                                       abEdge.fChild = bNode;
-                                                       edge bcEdge(bcEdgeStr, cNode);
-                                                       bNode->fChildren.push_back(bcEdge);
-                                                       bNode->addSymbol(fullStr, address, flags);
-                                                       return;
-                                               }
-                                       }
-                               }
-                       }
-                       // no commonality with any existing child, make a new edge that is this whole string
-                       node* newNode = new node(strdup(fullStr));
-                       edge newEdge(strdup(partialStr), newNode);
-                       fChildren.push_back(newEdge);
-                       newNode->fAddress = address;
-                       newNode->fFlags = flags;
-                       newNode->fHaveExportInfo = true;
-               }
-               
-               void addOrderedNodes(const char* name, std::vector<node*>& orderedNodes) {
-                       if ( !fOrdered ) {
-                               orderedNodes.push_back(this);
-                               //fprintf(stderr, "ordered %p %s\n", this, fCummulativeString);
-                               fOrdered = true;
-                       }
-                       const char* partialStr = &name[strlen(fCummulativeString)];
-                       for (typename std::vector<edge>::iterator it = fChildren.begin(); it != fChildren.end(); ++it) {
-                               edge& e = *it;
-                               int subStringLen = strlen(e.fSubString);
-                               if ( strncmp(e.fSubString, partialStr, subStringLen) == 0 ) {
-                                       // already have matching edge, go down that path
-                                       e.fChild->addOrderedNodes(name, orderedNodes);
-                                       return;
-                               }
-                       }
-               }
-
-               // byte for terminal node size in bytes, or 0x00 if not terminal node
-               // teminal node (uleb128 flags, uleb128 addr)
-               // byte for child node count
-               //  each child: zero terminated substring, uleb128 node offset
-               bool updateOffset(uint32_t& offset) {
-                       uint32_t nodeSize = 1; // byte for length of export info
-                       if ( fHaveExportInfo ) 
-                               nodeSize += ByteStream::uleb128_size(fFlags) + ByteStream::uleb128_size(fAddress);
-
-                       // add children
-                       ++nodeSize; // byte for count of chidren
-                       for (typename std::vector<edge>::iterator it = fChildren.begin(); it != fChildren.end(); ++it) {
-                               edge& e = *it;
-                               nodeSize += strlen(e.fSubString) + 1 + ByteStream::uleb128_size(e.fChild->fTrieOffset);
-                       }
-                       bool result = (fTrieOffset != offset);
-                       fTrieOffset = offset;
-                       //fprintf(stderr, "updateOffset %p %05d %s\n", this, fTrieOffset, fCummulativeString);
-                       offset += nodeSize;
-                       // return true if fTrieOffset was changed
-                       return result;
-               }
-       
-               void appendToStream(ByteStream& out) {
-                       if ( fHaveExportInfo ) {
-                               // nodes with export info: size, flags, address
-                               out.append_byte(out.uleb128_size(fFlags) + out.uleb128_size(fAddress));
-                               out.append_uleb128(fFlags);
-                               out.append_uleb128(fAddress);
-                       }
-                       else {
-                               // no export info
-                               out.append_byte(0);
-                       }
-                       // write number of children
-                       out.append_byte(fChildren.size());
-                       // write each child
-                       for (typename std::vector<edge>::iterator it = fChildren.begin(); it != fChildren.end(); ++it) {
-                               edge& e = *it;
-                               out.append_string(e.fSubString);
-                               out.append_uleb128(e.fChild->fTrieOffset);
-                       }
-               }
-       
-       };
-
-
-       struct node             fStartNode;
-};
-
-template <typename A>
-class LocalRelocationsLinkEditAtom : public LinkEditAtom<A>
-{
-public:
-                                                                                       LocalRelocationsLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
-       virtual const char*                                             getDisplayName() const  { return "local relocations"; }
-       virtual uint64_t                                                getSize() const;
-       virtual const char*                                             getSectionName() const  { return "._local_relocs"; }
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
-private:
-       using WriterAtom<A>::fWriter;
-       typedef typename A::P                                   P;
-};
-
-template <typename A>
-class SymbolTableLinkEditAtom : public LinkEditAtom<A>
-{
-public:
-                                                                                       SymbolTableLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
-       virtual const char*                                             getDisplayName() const  { return "symbol table"; }
-       virtual uint64_t                                                getSize() const;
-       virtual const char*                                             getSectionName() const  { return "._symbol_table"; }
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
-private:
-       using WriterAtom<A>::fWriter;
-       typedef typename A::P                                   P;
-};
-
-template <typename A>
-class ExternalRelocationsLinkEditAtom : public LinkEditAtom<A>
-{
-public:
-                                                                                       ExternalRelocationsLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
-       virtual const char*                                             getDisplayName() const  { return "external relocations"; }
-       virtual uint64_t                                                getSize() const;
-       virtual const char*                                             getSectionName() const  { return "._extern_relocs"; }
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
-private:
-       using WriterAtom<A>::fWriter;
-       typedef typename A::P                                   P;
-};
-
-struct IndirectEntry {
-       uint32_t        indirectIndex;
-       uint32_t        symbolIndex;
-};
-
-
-template <typename A>
-class SegmentSplitInfoContentAtom : public LinkEditAtom<A>
-{
-public:
-                                                                                       SegmentSplitInfoContentAtom(Writer<A>& writer) : LinkEditAtom<A>(writer), fCantEncode(false) { }
-       virtual const char*                                             getDisplayName() const  { return "split segment info"; }
-       virtual uint64_t                                                getSize() const;
-       virtual const char*                                             getSectionName() const  { return "._split_info"; }
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
-       bool                                                                    canEncode()                                             { return !fCantEncode; }
-       void                                                                    setCantEncode()                                 { fCantEncode = true; }
-       void                                                                    add32bitPointerLocation(const ObjectFile::Atom* atom, uint32_t offset) { fKind1Locations.push_back(AtomAndOffset(atom, offset)); }
-       void                                                                    add64bitPointerLocation(const ObjectFile::Atom* atom, uint32_t offset) { fKind2Locations.push_back(AtomAndOffset(atom, offset)); }
-       void                                                                    addPPCHi16Location(const ObjectFile::Atom* atom, uint32_t offset) { fKind3Locations.push_back(AtomAndOffset(atom, offset)); }
-       void                                                                    add32bitImportLocation(const ObjectFile::Atom* atom, uint32_t offset) { fKind4Locations.push_back(AtomAndOffset(atom, offset)); }
-       void                                                                    encode();
-
-private:
-       using WriterAtom<A>::fWriter;
-       typedef typename A::P                                   P;
-       typedef typename A::P::uint_t                   pint_t;
-       struct AtomAndOffset { 
-                       AtomAndOffset(const ObjectFile::Atom* a, uint32_t off) : atom(a), offset(off) {}
-                       const ObjectFile::Atom*         atom; 
-                       uint32_t                                        offset; 
-       };
-       void                                                                    uleb128EncodeAddresses(const std::vector<AtomAndOffset>& locations);
-       
-       std::vector<AtomAndOffset>                              fKind1Locations;
-       std::vector<AtomAndOffset>                              fKind2Locations;
-       std::vector<AtomAndOffset>                              fKind3Locations;
-       std::vector<AtomAndOffset>                              fKind4Locations;
-       std::vector<uint8_t>                                    fEncodedData;
-       bool                                                                    fCantEncode;
-};
-
-template <typename A>
-class IndirectTableLinkEditAtom : public LinkEditAtom<A>
-{
-public:
-                                                                                       IndirectTableLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer) { }
-       virtual const char*                                             getDisplayName() const  { return "indirect symbol table"; }
-       virtual uint64_t                                                getSize() const;
-       virtual const char*                                             getSectionName() const  { return "._indirect_syms"; }
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
-
-       std::vector<IndirectEntry>                              fTable;
-
-private:
-       using WriterAtom<A>::fWriter;
-       typedef typename A::P                                   P;
-};
-
-template <typename A>
-class ModuleInfoLinkEditAtom : public LinkEditAtom<A>
-{
-public:
-                                                                                       ModuleInfoLinkEditAtom(Writer<A>& writer) : LinkEditAtom<A>(writer), fModuleNameOffset(0) { }
-       virtual const char*                                             getDisplayName() const  { return "module table"; }
-       virtual uint64_t                                                getSize() const;
-       virtual const char*                                             getSectionName() const  { return "._module_info"; }
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
-
-                       void                                                    setName() { fModuleNameOffset = fWriter.fStringsAtom->add("single module"); }
-                       uint32_t                                                getTableOfContentsFileOffset() const;
-                       uint32_t                                                getModuleTableFileOffset() const;
-                       uint32_t                                                getReferencesFileOffset() const;
-                       uint32_t                                                getReferencesCount() const;
-
-private:
-       using WriterAtom<A>::fWriter;
-       typedef typename A::P                                   P;
-       typedef typename A::P::uint_t                   pint_t;
-       uint32_t                                                                fModuleNameOffset;
-};
-
-
-class CStringEquals
-{
-public:
-       bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
-};
-
-template <typename A>
-class StringsLinkEditAtom : public LinkEditAtom<A>
-{
-public:
-                                                                                       StringsLinkEditAtom(Writer<A>& writer);
-       virtual const char*                                             getDisplayName() const  { return "string pool"; }
-       virtual uint64_t                                                getSize() const;
-       virtual const char*                                             getSectionName() const  { return "._string_pool"; }
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
-
-       int32_t                                                                 add(const char* name);
-       int32_t                                                                 addUnique(const char* name);
-       int32_t                                                                 emptyString()                   { return 1; }
-       const char*                                                             stringForIndex(int32_t) const;
-
-private:
-       using WriterAtom<A>::fWriter;
-       typedef typename A::P                                   P;
-       enum { kBufferSize = 0x01000000 };
-       typedef __gnu_cxx::hash_map<const char*, int32_t, __gnu_cxx::hash<const char*>, CStringEquals> StringToOffset;
-
-       std::vector<char*>                                              fFullBuffers;
-       char*                                                                   fCurrentBuffer;
-       uint32_t                                                                fCurrentBufferUsed;
-       StringToOffset                                                  fUniqueStrings;
-};
-
-
-
-template <typename A>
-class UndefinedSymbolProxyAtom : public WriterAtom<A>
-{
-public:
-                                                                                                       UndefinedSymbolProxyAtom(Writer<A>& writer, const char* name) : WriterAtom<A>(writer, Segment::fgLinkEditSegment), fName(name) {}
-       virtual const char*                                                             getName() const                         { return fName; }
-       virtual ObjectFile::Atom::Scope                                 getScope() const                        { return ObjectFile::Atom::scopeGlobal; }
-       virtual ObjectFile::Atom::DefinitionKind                getDefinitionKind() const       { return ObjectFile::Atom::kExternalDefinition; }
-       virtual ObjectFile::Atom::SymbolTableInclusion  getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableIn; }
-       virtual uint64_t                                                                getSize() const                         { return 0; }
-       virtual const char*                                                             getSectionName() const          { return "._imports"; }
-private:
-       using WriterAtom<A>::fWriter;
-       typedef typename A::P                                   P;
-       const char*                                                             fName;
-};
-
-template <typename A>
-class BranchIslandAtom : public WriterAtom<A>
-{
-public:
-                                                                                       BranchIslandAtom(Writer<A>& writer, const char* name, int islandRegion, ObjectFile::Atom& target, 
-                                                                                                                                               ObjectFile::Atom& finalTarget, uint32_t finalTargetOffset);
-       virtual const char*                                             getName() const                         { return fName; }
-       virtual ObjectFile::Atom::Scope                 getScope() const                        { return ObjectFile::Atom::scopeLinkageUnit; }
-       virtual uint64_t                                                getSize() const;
-       virtual bool                                                    isThumb() const                         { return (fIslandKind == kBranchIslandToThumb2); }
-       virtual ObjectFile::Atom::ContentType   getContentType() const          { return ObjectFile::Atom::kBranchIsland; }
-       virtual ObjectFile::Atom::SymbolTableInclusion  getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableIn; }
-       virtual const char*                                             getSectionName() const          { return "__text"; }
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
-       uint64_t                                                                getFinalTargetAdress() const { return fFinalTarget.getAddress() + fFinalTargetOffset; }
-private:
-       using WriterAtom<A>::fWriter;
-       enum IslandKind { kBranchIslandToARM, kBranchIslandToThumb2, kBranchIslandToThumb1, kBranchIslandNoPicToThumb1 };
-       const char*                                                             fName;
-       ObjectFile::Atom&                                               fTarget;
-       ObjectFile::Atom&                                               fFinalTarget;
-       uint32_t                                                                fFinalTargetOffset;
-       IslandKind                                                              fIslandKind;
-};
-
-template <typename A>
-class StubAtom : public WriterAtom<A>
-{
-public:
-                                                                                       StubAtom(Writer<A>& writer, ObjectFile::Atom& target, bool forLazyDylib);
-       virtual const char*                                             getName() const                         { return fName; }
-       virtual ObjectFile::Atom::Scope                 getScope() const                        { return ObjectFile::Atom::scopeLinkageUnit; }
-       virtual ObjectFile::Atom::ContentType   getContentType() const          { return ObjectFile::Atom::kStub; }
-       virtual uint64_t                                                getSize() const;
-       virtual ObjectFile::Alignment                   getAlignment() const;
-       virtual const char*                                             getSectionName() const          { return "__symbol_stub1"; }
-       virtual std::vector<ObjectFile::Reference*>&  getReferences() const             { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
-       ObjectFile::Atom*                                               getTarget()                                     { return &fTarget; }
-       virtual uint32_t                                                getOrdinal() const                      { return fSortingOrdinal; }
-       void                                                                    setSortingOrdinal(uint32_t o) { fSortingOrdinal = o; }
-private:
-       static const char*                                              stubName(const char* importName);
-       friend class LazyPointerAtom<A>;
-       using WriterAtom<A>::fWriter;
-       enum StubKind { kStubPIC, kStubNoPIC, kStubShort, kJumpTable };
-       const char*                                                             fName;
-       ObjectFile::Atom&                                               fTarget;
-       std::vector<ObjectFile::Reference*>             fReferences;
-       bool                                                                    fForLazyDylib;
-       StubKind                                                                fKind;
-       uint32_t                                                                fSortingOrdinal;
-};
-
-
-template <typename A>
-class FastStubHelperHelperAtom : public WriterAtom<A>
-{
-public:
-                                                                                                       FastStubHelperHelperAtom(Writer<A>& writer);
-       virtual const char*                                                             getName() const                                 { return " stub helpers"; }  // name sorts to start of helpers
-       virtual ObjectFile::Atom::SymbolTableInclusion  getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableIn; }
-       virtual ObjectFile::Atom::Scope                                 getScope() const                                { return ObjectFile::Atom::scopeLinkageUnit; }
-       virtual ObjectFile::Atom::ContentType                   getContentType() const                  { return ObjectFile::Atom::kStubHelper; }
-       virtual uint64_t                                                                getSize() const;
-       virtual const char*                                                             getSectionName() const                  { return "__stub_helper"; }
-       virtual std::vector<ObjectFile::Reference*>&    getReferences() const                   { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
-       virtual void                                                                    copyRawContent(uint8_t buffer[]) const;
-       virtual ObjectFile::Alignment                                   getAlignment() const                    { return ObjectFile::Alignment(0); }
-       virtual uint32_t                                                                getOrdinal() const                              { return 0; }
-protected:
-       using WriterAtom<A>::fWriter;
-       std::vector<ObjectFile::Reference*>             fReferences;
-};
-
-template <typename A>
-class HybridStubHelperHelperAtom : public WriterAtom<A>
-{
-public:
-                                                                                                       HybridStubHelperHelperAtom(Writer<A>& writer);
-       virtual const char*                                                             getName() const                                 { return " stub helpers"; }  // name sorts to start of helpers
-       virtual ObjectFile::Atom::SymbolTableInclusion  getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableIn; }
-       virtual ObjectFile::Atom::Scope                                 getScope() const                                { return ObjectFile::Atom::scopeLinkageUnit; }
-       virtual ObjectFile::Atom::ContentType                   getContentType() const                  { return ObjectFile::Atom::kStubHelper; }
-       virtual uint64_t                                                                getSize() const;
-       virtual const char*                                                             getSectionName() const                  { return "__stub_helper"; }
-       virtual std::vector<ObjectFile::Reference*>&    getReferences() const                   { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
-       virtual void                                                                    copyRawContent(uint8_t buffer[]) const;
-       virtual ObjectFile::Alignment                                   getAlignment() const                    { return ObjectFile::Alignment(0); }
-       virtual uint32_t                                                                getOrdinal() const                              { return 0; }
-protected:
-       using WriterAtom<A>::fWriter;
-       std::vector<ObjectFile::Reference*>             fReferences;
-};
-
-template <typename A>
-class StubHelperAtom : public WriterAtom<A>
-{
-public:
-                                                                                       StubHelperAtom(Writer<A>& writer, ObjectFile::Atom& target, 
-                                                                                                               LazyPointerAtom<A>& lazyPointer, bool forLazyDylib) 
-                                                                                                       : WriterAtom<A>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), 
-                                                                                                               fTarget(target), fLazyPointerAtom(lazyPointer) {
-                                                                                                                       writer.fAllSynthesizedStubHelpers.push_back(this);
-                                                                                                               }
-
-       virtual const char*                                             getName() const                         { return fName; }
-       virtual ObjectFile::Atom::Scope                 getScope() const                        { return ObjectFile::Atom::scopeLinkageUnit; }
-       virtual ObjectFile::Atom::ContentType   getContentType() const          { return ObjectFile::Atom::kStubHelper; }
-       virtual const char*                                             getSectionName() const          { return "__stub_helper"; }
-       virtual std::vector<ObjectFile::Reference*>&  getReferences() const     { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
-       ObjectFile::Atom*                                               getTarget()                                     { return &fTarget; }
-       virtual ObjectFile::Alignment                   getAlignment() const            { return ObjectFile::Alignment(0); }
-       virtual uint32_t                                                getOrdinal() const                      { return 1; }
-protected:
-       static const char*                                              stubName(const char* importName);
-       using WriterAtom<A>::fWriter;
-       const char*                                                             fName;
-       ObjectFile::Atom&                                               fTarget;
-       LazyPointerAtom<A>&                                             fLazyPointerAtom;
-       std::vector<ObjectFile::Reference*>             fReferences;
-};
-                                                                               
-template <typename A>
-class ClassicStubHelperAtom : public StubHelperAtom<A>
-{
-public:
-                                                                                       ClassicStubHelperAtom(Writer<A>& writer, ObjectFile::Atom& target, 
-                                                                                                                       class LazyPointerAtom<A>& lazyPointer, bool forLazyDylib);
-
-       virtual uint64_t                                                getSize() const;
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
-};                                                                                             
-
-
-template <typename A>
-class HybridStubHelperAtom : public StubHelperAtom<A>
-{
-public:
-                                                                                       HybridStubHelperAtom(Writer<A>& writer, ObjectFile::Atom& target, 
-                                                                                                                       class LazyPointerAtom<A>& lazyPointer, bool forLazyDylib);
-
-       virtual uint64_t                                                getSize() const;
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
-       static class HybridStubHelperHelperAtom<A>*     fgHelperHelperAtom;
-};                                                                                             
-template <typename A> class HybridStubHelperHelperAtom<A>* HybridStubHelperAtom<A>::fgHelperHelperAtom = NULL;
-
-template <typename A>
-class FastStubHelperAtom : public StubHelperAtom<A>
-{
-public:
-                                                                                       FastStubHelperAtom(Writer<A>& writer, ObjectFile::Atom& target, 
-                                                                                                                               class LazyPointerAtom<A>& lazyPointer, bool forLazyDylib);
-       virtual uint64_t                                                getSize() const;
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
-       static FastStubHelperHelperAtom<A>*             fgHelperHelperAtom;
-};                                     
-template <typename A>  FastStubHelperHelperAtom<A>* FastStubHelperAtom<A>::fgHelperHelperAtom = NULL;
-                       
-
-
-template <typename A>
-class LazyPointerAtom : public WriterAtom<A>
-{
-public:
-                                                                                       LazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target, 
-                                                                                                                       StubAtom<A>& stub, bool forLazyDylib);
-       virtual const char*                                             getName() const                         { return fName; }
-       virtual ObjectFile::Atom::Scope                 getScope() const                        { return ObjectFile::Atom::scopeTranslationUnit; }
-       virtual ObjectFile::Atom::ContentType   getContentType() const          { return fForLazyDylib ? ObjectFile::Atom::kLazyDylibPointer : ObjectFile::Atom::kLazyPointer; }
-       virtual uint64_t                                                getSize() const                         { return sizeof(typename A::P::uint_t); }
-       virtual const char*                                             getSectionName() const;
-       virtual std::vector<ObjectFile::Reference*>&  getReferences() const             { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
-       ObjectFile::Atom*                                               getTarget()                                     { return &fExternalTarget; }
-       void                                                                    setLazyBindingInfoOffset(uint32_t off) { fLazyBindingOffset = off; }
-       uint32_t                                                                getLazyBindingInfoOffset()      { return fLazyBindingOffset; }
-       virtual uint32_t                                                getOrdinal() const                      { return fSortingOrdinal; }
-       void                                                                    setSortingOrdinal(uint32_t o) { fSortingOrdinal = o; }
-private:
-       using WriterAtom<A>::fWriter;
-       static const char*                                              lazyPointerName(const char* importName);
-       const char*                                                             fName;
-       ObjectFile::Atom&                                               fTarget;
-       ObjectFile::Atom&                                               fExternalTarget;
-       std::vector<ObjectFile::Reference*>             fReferences;
-       bool                                                                    fForLazyDylib;
-       bool                                                                    fCloseStub;
-       uint32_t                                                                fLazyBindingOffset;
-       uint32_t                                                                fSortingOrdinal;
-};
-
-
-template <typename A>
-class NonLazyPointerAtom : public WriterAtom<A>
-{
-public:
-                                                                                       NonLazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target);
-                                                                                       NonLazyPointerAtom(Writer<A>& writer, const char* targetName);
-                                                                                       NonLazyPointerAtom(Writer<A>& writer);
-       virtual const char*                                             getName() const                         { return fName; }
-       virtual ObjectFile::Atom::Scope                 getScope() const                        { return ObjectFile::Atom::scopeLinkageUnit; }
-       virtual ObjectFile::Atom::ContentType   getContentType() const          { return ObjectFile::Atom::kNonLazyPointer; }
-       virtual uint64_t                                                getSize() const                         { return sizeof(typename A::P::uint_t); }
-       virtual const char*                                             getSectionName() const          { return (fWriter.fOptions.outputKind() == Options::kKextBundle) ? "__got" : "__nl_symbol_ptr"; }
-       virtual std::vector<ObjectFile::Reference*>&  getReferences() const             { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
-       ObjectFile::Atom*                                               getTarget()                                     { return fTarget; }
-       virtual uint32_t                                                getOrdinal() const                      { return fSortingOrdinal; }
-       void                                                                    setSortingOrdinal(uint32_t o) { fSortingOrdinal = o; }
-private:
-       using WriterAtom<A>::fWriter;
-       static const char*                                              nonlazyPointerName(const char* importName);
-       const char*                                                             fName;
-       ObjectFile::Atom*                                               fTarget;
-       std::vector<ObjectFile::Reference*>             fReferences;
-       uint32_t                                                                fSortingOrdinal;
-};
-
-
-template <typename A>
-class ObjCInfoAtom : public WriterAtom<A>
-{
-public:
-                                                                                       ObjCInfoAtom(Writer<A>& writer, ObjectFile::Reader::ObjcConstraint objcContraint,
-                                                                                                               bool objcReplacementClasses, bool abi2override);
-       virtual const char*                                             getName() const                         { return "objc$info"; }
-       virtual ObjectFile::Atom::Scope                 getScope() const                        { return ObjectFile::Atom::scopeLinkageUnit; }
-       virtual uint64_t                                                getSize() const                         { return 8; }
-       virtual const char*                                             getSectionName() const;
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
-private:
-       Segment&                                                                getInfoSegment(bool abi2override) const;
-       bool                                                                    fAbi2override;
-       uint32_t                                                                fContent[2];
-};
-
-
-template <typename A>
-class WriterReference : public ObjectFile::Reference
-{
-public:
-       typedef typename A::ReferenceKinds                      Kinds;
-
-                                                       WriterReference(uint32_t offset, Kinds kind, ObjectFile::Atom* target,
-                                                                                       uint32_t toOffset=0, ObjectFile::Atom* fromTarget=NULL, uint32_t fromOffset=0)
-                                                                                 : fKind(kind), fFixUpOffsetInSrc(offset), fTarget(target), fTargetName(target->getName()),
-                                                                                       fTargetOffset(toOffset), fFromTarget(fromTarget), fFromTargetOffset(fromOffset) {}
-                                                       WriterReference(uint32_t offset, Kinds kind, const char* targetName)
-                                                                                 : fKind(kind), fFixUpOffsetInSrc(offset), fTarget(NULL), fTargetName(targetName),
-                                                                                       fTargetOffset(0), fFromTarget(NULL), fFromTargetOffset(0) {}
-
-       virtual                                 ~WriterReference() {}
-
-       virtual ObjectFile::Reference::TargetBinding getTargetBinding() const { return (fTarget != NULL) ? ObjectFile::Reference::kBoundDirectly :  ObjectFile::Reference::kUnboundByName; }
-       virtual ObjectFile::Reference::TargetBinding getFromTargetBinding() const { return (fFromTarget != NULL) ? ObjectFile::Reference::kBoundDirectly : ObjectFile::Reference::kDontBind; }
-       virtual uint8_t                 getKind() const                                                                 { return (uint8_t)fKind; }
-       virtual uint64_t                getFixUpOffset() const                                                  { return fFixUpOffsetInSrc; }
-       virtual const char*             getTargetName() const                                                   { return fTargetName; }
-       virtual ObjectFile::Atom& getTarget() const                                                             { return *fTarget; }
-       virtual uint64_t                getTargetOffset() const                                                 { return fTargetOffset; }
-       virtual ObjectFile::Atom& getFromTarget() const                                                 { return *fFromTarget; }
-       virtual const char*             getFromTargetName() const                                               { return fFromTarget->getName(); }
-       virtual void                    setTarget(ObjectFile::Atom& target, uint64_t offset)    { fTarget = &target; fTargetOffset = offset; }
-       virtual void                    setFromTarget(ObjectFile::Atom& target)                 { fFromTarget = &target; }
-       virtual void                    setFromTargetName(const char* name)                             {  }
-       virtual void                    setFromTargetOffset(uint64_t offset)                    { fFromTargetOffset = offset; }
-       virtual const char*             getDescription() const                                                  { return "writer reference"; }
-       virtual uint64_t                getFromTargetOffset() const                                             { return fFromTargetOffset; }
-
-private:
-       Kinds                                   fKind;
-       uint32_t                                fFixUpOffsetInSrc;
-       ObjectFile::Atom*               fTarget;
-       const char*                             fTargetName;
-       uint32_t                                fTargetOffset;
-       ObjectFile::Atom*               fFromTarget;
-       uint32_t                                fFromTargetOffset;
-};
-
-
-template <typename A>
-const char* StubHelperAtom<A>::stubName(const char* name)
-{
-       char* buf;
-       asprintf(&buf, "%s$stubHelper", name);
-       return buf;
-}
-
-template <>
-ClassicStubHelperAtom<x86_64>::ClassicStubHelperAtom(Writer<x86_64>& writer, ObjectFile::Atom& target, 
-                                                                                                                       class LazyPointerAtom<x86_64>& lazyPointer, bool forLazyDylib)
-       : StubHelperAtom<x86_64>(writer, target, lazyPointer, forLazyDylib)
-{
-       fReferences.push_back(new WriterReference<x86_64>(3, x86_64::kPCRel32, &fLazyPointerAtom));
-       if ( forLazyDylib ) {
-               if ( fWriter.fDyldLazyDylibHelper == NULL )
-                       throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
-               fReferences.push_back(new WriterReference<x86_64>(8, x86_64::kPCRel32, fWriter.fDyldLazyDylibHelper));
-       }
-       else {
-               if ( fWriter.fDyldClassicHelperAtom == NULL )
-                       throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
-               fReferences.push_back(new WriterReference<x86_64>(8, x86_64::kPCRel32, fWriter.fDyldClassicHelperAtom));
-       }
-}
-
-
-template <>
-uint64_t ClassicStubHelperAtom<x86_64>::getSize() const
-{
-       return 12;
-}
-
-template <>
-void ClassicStubHelperAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
-{
-       buffer[0]  = 0x4C;              // lea foo$lazy_ptr(%rip),%r11
-       buffer[1]  = 0x8D;
-       buffer[2]  = 0x1D;
-       buffer[3]  = 0x00;
-       buffer[4]  = 0x00;
-       buffer[5]  = 0x00;
-       buffer[6]  = 0x00;
-       buffer[7]  = 0xE9;              // jmp dyld_stub_binding_helper
-       buffer[8]  = 0x00;
-       buffer[9]  = 0x00;
-       buffer[10] = 0x00;
-       buffer[11] = 0x00;
-}
-
-
-template <>
-FastStubHelperHelperAtom<x86_64>::FastStubHelperHelperAtom(Writer<x86_64>& writer)
-       : WriterAtom<x86_64>(writer, Segment::fgTextSegment)
-{
-       fReferences.push_back(new WriterReference<x86_64>(3, x86_64::kPCRel32, new NonLazyPointerAtom<x86_64>(writer)));
-       fReferences.push_back(new WriterReference<x86_64>(11, x86_64::kPCRel32, writer.fFastStubGOTAtom));
-}
-
-template <>
-uint64_t FastStubHelperHelperAtom<x86_64>::getSize() const
-{
-       return 16;
-}
-
-template <>
-void FastStubHelperHelperAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
-{
-       buffer[0]  = 0x4C;              // leaq dyld_mageLoaderCache(%rip),%r11
-       buffer[1]  = 0x8D;
-       buffer[2]  = 0x1D;
-       buffer[3]  = 0x00;
-       buffer[4]  = 0x00;
-       buffer[5]  = 0x00;
-       buffer[6]  = 0x00;
-       buffer[7]  = 0x41;              // pushq %r11
-       buffer[8]  = 0x53;
-       buffer[9]  = 0xFF;              // jmp *_fast_lazy_bind(%rip)
-       buffer[10] = 0x25;
-       buffer[11] = 0x00;
-       buffer[12] = 0x00;
-       buffer[13] = 0x00;
-       buffer[14] = 0x00;
-       buffer[15] = 0x90;              // nop
-}
-
-
-template <>
-HybridStubHelperHelperAtom<x86_64>::HybridStubHelperHelperAtom(Writer<x86_64>& writer)
-       : WriterAtom<x86_64>(writer, Segment::fgTextSegment)
-{
-       if ( writer.fDyldClassicHelperAtom == NULL )
-               throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
-       fReferences.push_back(new WriterReference<x86_64>(3, x86_64::kPCRel32_1, writer.fFastStubGOTAtom));
-       fReferences.push_back(new WriterReference<x86_64>(13, x86_64::kPCRel32, new NonLazyPointerAtom<x86_64>(writer)));
-       fReferences.push_back(new WriterReference<x86_64>(21, x86_64::kPCRel32, writer.fFastStubGOTAtom));
-       fReferences.push_back(new WriterReference<x86_64>(30, x86_64::kPCRel32, writer.fDyldClassicHelperAtom));
-}
-
-template <>
-uint64_t HybridStubHelperHelperAtom<x86_64>::getSize() const
-{
-       return 34;
-}
-
-template <>
-void HybridStubHelperHelperAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
-{
-       buffer[0]  = 0x48;              // cmpl $0x00,_fast_lazy_bind
-       buffer[1]  = 0x83;              
-       buffer[2]  = 0x3D;
-       buffer[3]  = 0x00;              
-       buffer[4]  = 0x00;
-       buffer[5]  = 0x00;
-       buffer[6]  = 0x00;
-       buffer[7]  = 0x00;
-       buffer[8]  = 0x74;              // je 16
-       buffer[9]  = 0x0F;              
-       buffer[10] = 0x4C;              // leaq imageCache(%rip),%r11
-       buffer[11] = 0x8D;              
-       buffer[12] = 0x1D;              
-       buffer[13] = 0x00;              
-       buffer[14] = 0x00;
-       buffer[15] = 0x00;
-       buffer[16] = 0x00;
-       buffer[17] = 0x41;              // pushq %r11
-       buffer[18] = 0x53;
-       buffer[19] = 0xFF;              // jmp *_fast_lazy_bind(%rip)
-       buffer[20] = 0x25;      
-       buffer[21] = 0x00;
-       buffer[22] = 0x00;
-       buffer[23] = 0x00;
-       buffer[24] = 0x00;
-       buffer[25] = 0x48;              // addq $8,%rsp
-       buffer[26] = 0x83;
-       buffer[27] = 0xC4;
-       buffer[28] = 0x08;
-       buffer[29] = 0xE9;              // jmp dyld_stub_binding_helper
-       buffer[30] = 0x00;
-       buffer[31] = 0x00;
-       buffer[32] = 0x00;
-       buffer[33] = 0x00;
-}
-
-
-template <>
-HybridStubHelperAtom<x86_64>::HybridStubHelperAtom(Writer<x86_64>& writer, ObjectFile::Atom& target, 
-                                                                                                                       class LazyPointerAtom<x86_64>& lazyPointer, bool forLazyDylib)
-       : StubHelperAtom<x86_64>(writer, target, lazyPointer, forLazyDylib)
-{
-       if ( fgHelperHelperAtom == NULL ) {
-               fgHelperHelperAtom = new HybridStubHelperHelperAtom<x86_64>::HybridStubHelperHelperAtom(fWriter);
-               fWriter.fAllSynthesizedStubHelpers.push_back(fgHelperHelperAtom);
-       }
-       fReferences.push_back(new WriterReference<x86_64>(8,  x86_64::kPCRel32, &fLazyPointerAtom));
-       fReferences.push_back(new WriterReference<x86_64>(13, x86_64::kPCRel32, fgHelperHelperAtom));
-}
-
-template <>
-uint64_t HybridStubHelperAtom<x86_64>::getSize() const
-{
-       return 18;
-}
-
-template <>
-void HybridStubHelperAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
-{
-       buffer[0]  = 0x68;              // pushq $lazy-info-offset
-       buffer[1]  = 0x00;
-       buffer[2]  = 0x00;
-       buffer[3]  = 0x00;
-       buffer[4]  = 0x00;
-       buffer[5]  = 0x4C;              // lea foo$lazy_ptr(%rip),%r11
-       buffer[6]  = 0x8D;
-       buffer[7]  = 0x1D;
-       buffer[8]  = 0x00;
-       buffer[9]  = 0x00;
-       buffer[10] = 0x00;
-       buffer[11] = 0x00;
-       buffer[12] = 0xE9;              // jmp helper-helper
-       buffer[13] = 0x00;
-       buffer[14] = 0x00;
-       buffer[15] = 0x00;
-       buffer[16] = 0x00;
-       buffer[17] = 0x90;              // nop
-       
-       // the lazy binding info is created later than this helper atom, so there
-       // is no Reference to update.  Instead we blast the offset here.
-       uint32_t offset;
-       LittleEndian::set32(offset, fLazyPointerAtom.getLazyBindingInfoOffset());
-       memcpy(&buffer[1], &offset, 4);
-}
-
-template <>
-FastStubHelperAtom<x86_64>::FastStubHelperAtom(Writer<x86_64>& writer, ObjectFile::Atom& target, 
-                                                                                                                       class LazyPointerAtom<x86_64>& lazyPointer, bool forLazyDylib)
-       : StubHelperAtom<x86_64>(writer, target, lazyPointer, forLazyDylib)
-{
-       if ( fgHelperHelperAtom == NULL ) {
-               fgHelperHelperAtom = new FastStubHelperHelperAtom<x86_64>::FastStubHelperHelperAtom(fWriter);
-               fWriter.fAllSynthesizedStubHelpers.push_back(fgHelperHelperAtom);
-       }
-       fReferences.push_back(new WriterReference<x86_64>(6, x86_64::kPCRel32, fgHelperHelperAtom));
-}
-
-template <>
-uint64_t FastStubHelperAtom<x86_64>::getSize() const
-{
-       return 10;
-}
-
-template <>
-void FastStubHelperAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
-{
-       buffer[0]  = 0x68;              // pushq $lazy-info-offset
-       buffer[1]  = 0x00;
-       buffer[2]  = 0x00;
-       buffer[3]  = 0x00;
-       buffer[4]  = 0x00;
-       buffer[5]  = 0xE9;              // jmp helperhelper
-       buffer[6]  = 0x00;
-       buffer[7]  = 0x00;
-       buffer[8]  = 0x00;
-       buffer[9]  = 0x00;
-       
-       // the lazy binding info is created later than this helper atom, so there
-       // is no Reference to update.  Instead we blast the offset here.
-       uint32_t offset;
-       LittleEndian::set32(offset, fLazyPointerAtom.getLazyBindingInfoOffset());
-       memcpy(&buffer[1], &offset, 4);
-}
-
-template <>
-FastStubHelperHelperAtom<x86>::FastStubHelperHelperAtom(Writer<x86>& writer)
-       : WriterAtom<x86>(writer, Segment::fgTextSegment)
-{
-       fReferences.push_back(new WriterReference<x86>(1, x86::kAbsolute32, new NonLazyPointerAtom<x86>(writer)));
-       fReferences.push_back(new WriterReference<x86>(7, x86::kAbsolute32, writer.fFastStubGOTAtom));
-}
-
-template <>
-uint64_t FastStubHelperHelperAtom<x86>::getSize() const
-{
-       return 12;
-}
-
-template <>
-void FastStubHelperHelperAtom<x86>::copyRawContent(uint8_t buffer[]) const
-{
-       buffer[0]  = 0x68;              // pushl $dyld_ImageLoaderCache
-       buffer[1]  = 0x00;
-       buffer[2]  = 0x00;
-       buffer[3]  = 0x00;
-       buffer[4]  = 0x00;
-       buffer[5]  = 0xFF;              // jmp *_fast_lazy_bind
-       buffer[6]  = 0x25;
-       buffer[7]  = 0x00;
-       buffer[8]  = 0x00;
-       buffer[9]  = 0x00;
-       buffer[10] = 0x00;
-       buffer[11] = 0x90;              // nop
-}
-
-
-template <>
-FastStubHelperHelperAtom<arm>::FastStubHelperHelperAtom(Writer<arm>& writer)
-       : WriterAtom<arm>(writer, Segment::fgTextSegment)
-{
-       fReferences.push_back(new WriterReference<arm>(28, arm::kPointerDiff, new NonLazyPointerAtom<arm>(writer), 0, this, 16));
-       fReferences.push_back(new WriterReference<arm>(32, arm::kPointerDiff, writer.fFastStubGOTAtom, 0, this, 28));
-}
-
-template <>
-uint64_t FastStubHelperHelperAtom<arm>::getSize() const
-{
-       return 36;
-}
-
-template <>
-void FastStubHelperHelperAtom<arm>::copyRawContent(uint8_t buffer[]) const
-{
-       // push lazy-info-offset
-       OSWriteLittleInt32(&buffer[ 0], 0, 0xe52dc004); // str ip, [sp, #-4]!
-       // push address of dyld_mageLoaderCache
-       OSWriteLittleInt32(&buffer[ 4], 0, 0xe59fc010); // ldr  ip, L1
-       OSWriteLittleInt32(&buffer[ 8], 0, 0xe08fc00c); // add  ip, pc, ip
-       OSWriteLittleInt32(&buffer[12], 0, 0xe52dc004); // str ip, [sp, #-4]!
-       // jump through _fast_lazy_bind
-       OSWriteLittleInt32(&buffer[16], 0, 0xe59fc008); // ldr  ip, L2
-       OSWriteLittleInt32(&buffer[20], 0, 0xe08fc00c); // add  ip, pc, ip
-       OSWriteLittleInt32(&buffer[24], 0, 0xe59cf000); // ldr  pc, [ip]
-       OSWriteLittleInt32(&buffer[28], 0, 0x00000000); // L1: .long fFastStubGOTAtom - (helperhelper+16)
-       OSWriteLittleInt32(&buffer[32], 0, 0x00000000); // L2: .long _fast_lazy_bind - (helperhelper+28)
-}
-
-template <>
-ObjectFile::Alignment StubHelperAtom<arm>::getAlignment() const                { return ObjectFile::Alignment(2); }
-
-template <>
-FastStubHelperAtom<arm>::FastStubHelperAtom(Writer<arm>& writer, ObjectFile::Atom& target, 
-                                                                                       class LazyPointerAtom<arm>& lazyPointer, bool forLazyDylib)
-       : StubHelperAtom<arm>(writer, target, lazyPointer, forLazyDylib)
-{
-       if ( fgHelperHelperAtom == NULL ) {
-               fgHelperHelperAtom = new FastStubHelperHelperAtom<arm>::FastStubHelperHelperAtom(fWriter);
-               fWriter.fAllSynthesizedStubHelpers.push_back(fgHelperHelperAtom);
-       }
-       fReferences.push_back(new WriterReference<arm>(4, arm::kBranch24, fgHelperHelperAtom));
-}
-
-template <>
-uint64_t FastStubHelperAtom<arm>::getSize() const
-{
-       return 12;
-}
-
-template <>
-void FastStubHelperAtom<arm>::copyRawContent(uint8_t buffer[]) const
-{
-       OSWriteLittleInt32(&buffer[0], 0, 0xe59fc000); // ldr  ip, [pc, #0]
-       OSWriteLittleInt32(&buffer[4], 0, 0xea000000); // b     _helperhelper
-       // the lazy binding info is created later than this helper atom, so there
-       // is no Reference to update.  Instead we blast the offset here.
-       OSWriteLittleInt32(&buffer[8], 0, fLazyPointerAtom.getLazyBindingInfoOffset());
-}
-
-
-template <>
-HybridStubHelperHelperAtom<x86>::HybridStubHelperHelperAtom(Writer<x86>& writer)
-       : WriterAtom<x86>(writer, Segment::fgTextSegment)
-{
-       if ( writer.fDyldClassicHelperAtom == NULL )
-               throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
-       fReferences.push_back(new WriterReference<x86>(2,  x86::kAbsolute32, writer.fFastStubGOTAtom));
-       fReferences.push_back(new WriterReference<x86>(18, x86::kPCRel32, writer.fDyldClassicHelperAtom));
-       fReferences.push_back(new WriterReference<x86>(26, x86::kAbsolute32, new NonLazyPointerAtom<x86>(writer)));
-       fReferences.push_back(new WriterReference<x86>(32, x86::kAbsolute32, writer.fFastStubGOTAtom));
-}
-
-template <>
-uint64_t HybridStubHelperHelperAtom<x86>::getSize() const
-{
-       return 36;
-}
-
-
-template <>
-void HybridStubHelperHelperAtom<x86>::copyRawContent(uint8_t buffer[]) const
-{
-       buffer[0]  = 0x83;              // cmpl $0x00,_fast_lazy_bind
-       buffer[1]  = 0x3D;
-       buffer[2]  = 0x00;              
-       buffer[3]  = 0x00;
-       buffer[4]  = 0x00;
-       buffer[5]  = 0x00;
-       buffer[6]  = 0x00;
-       buffer[7]  = 0x75;              // jne 22
-       buffer[8]  = 0x0D;
-       buffer[9]  = 0x89;              // %eax,4(%esp)
-       buffer[10] = 0x44;
-       buffer[11] = 0x24;
-       buffer[12] = 0x04;
-       buffer[13] = 0x58;              // popl  %eax
-       buffer[14] = 0x87;              // xchgl (%esp),%eax
-       buffer[15] = 0x04;
-       buffer[16] = 0x24;
-       buffer[17] = 0xE9;              // jmpl dyld_stub_binding_helper
-       buffer[18] = 0x00;
-       buffer[19] = 0x00;
-       buffer[20] = 0x00;              
-       buffer[21] = 0x00;              
-       buffer[22] = 0x83;              // addl $0x04,%esp
-       buffer[23] = 0xC4;
-       buffer[24] = 0x04;
-       buffer[25] = 0x68;              // pushl imageloadercahce
-       buffer[26] = 0x00;
-       buffer[27] = 0x00;
-       buffer[28] = 0x00;
-       buffer[29] = 0x00;              
-       buffer[30] = 0xFF;              // jmp *_fast_lazy_bind(%rip)
-       buffer[31] = 0x25;      
-       buffer[32] = 0x00;
-       buffer[33] = 0x00;
-       buffer[34] = 0x00;
-       buffer[35] = 0x00;      
-}
-
-
-template <>
-ClassicStubHelperAtom<x86>::ClassicStubHelperAtom(Writer<x86>& writer, ObjectFile::Atom& target, 
-                                                                                                                       class LazyPointerAtom<x86>& lazyPointer, bool forLazyDylib)
-       : StubHelperAtom<x86>(writer, target, lazyPointer, forLazyDylib)
-{
-       fReferences.push_back(new WriterReference<x86>(1, x86::kAbsolute32, &fLazyPointerAtom));
-       if ( forLazyDylib ) {
-               if ( fWriter.fDyldLazyDylibHelper == NULL )
-                       throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
-               fReferences.push_back(new WriterReference<x86>(6, x86::kPCRel32, fWriter.fDyldLazyDylibHelper));
-       }
-       else {
-               if ( fWriter.fDyldClassicHelperAtom == NULL )
-                       throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
-               fReferences.push_back(new WriterReference<x86>(6, x86::kPCRel32, fWriter.fDyldClassicHelperAtom));
-       }
-}
-
-template <>
-uint64_t ClassicStubHelperAtom<x86>::getSize() const
-{
-       return 10;
-}
-
-template <>
-void ClassicStubHelperAtom<x86>::copyRawContent(uint8_t buffer[]) const
-{
-       buffer[0]  = 0x68;              // pushl $foo$lazy_ptr
-       buffer[1]  = 0x00;
-       buffer[2]  = 0x00;
-       buffer[3]  = 0x00;
-       buffer[4]  = 0x00;
-       buffer[5]  = 0xE9;              // jmp helperhelper
-       buffer[6]  = 0x00;
-       buffer[7]  = 0x00;
-       buffer[8]  = 0x00;
-       buffer[9]  = 0x00;
-}
-
-template <>
-HybridStubHelperAtom<x86>::HybridStubHelperAtom(Writer<x86>& writer, ObjectFile::Atom& target, 
-                                                                                                                       class LazyPointerAtom<x86>& lazyPointer, bool forLazyDylib)
-       : StubHelperAtom<x86>(writer, target, lazyPointer, forLazyDylib)
-{
-       if ( fgHelperHelperAtom == NULL ) {
-               fgHelperHelperAtom = new HybridStubHelperHelperAtom<x86>::HybridStubHelperHelperAtom(fWriter);
-               fWriter.fAllSynthesizedStubHelpers.push_back(fgHelperHelperAtom);
-       }       
-       fReferences.push_back(new WriterReference<x86>(6,  x86::kAbsolute32, &fLazyPointerAtom));
-       fReferences.push_back(new WriterReference<x86>(11, x86::kPCRel32, fgHelperHelperAtom));
-}
-
-
-template <>
-uint64_t HybridStubHelperAtom<x86>::getSize() const
-{
-       return 16;
-}
-
-template <>
-void HybridStubHelperAtom<x86>::copyRawContent(uint8_t buffer[]) const
-{
-       buffer[0]  = 0x68;              // pushl $lazy-info-offset
-       buffer[1]  = 0x00;
-       buffer[2]  = 0x00;
-       buffer[3]  = 0x00;
-       buffer[4]  = 0x00;
-       buffer[5]  = 0x68;              // pushl $foo$lazy_ptr
-       buffer[6]  = 0x00;
-       buffer[7]  = 0x00;
-       buffer[8]  = 0x00;
-       buffer[9]  = 0x00;
-       buffer[10] = 0xE9;              // jmp dyld_hybrid_stub_binding_helper
-       buffer[11] = 0x00;
-       buffer[12] = 0x00;
-       buffer[13] = 0x00;
-       buffer[14] = 0x00;
-       buffer[15] = 0x90;              // nop
-       
-       // the lazy binding info is created later than this helper atom, so there
-       // is no Reference to update.  Instead we blast the offset here.
-       uint32_t offset;
-       LittleEndian::set32(offset, fLazyPointerAtom.getLazyBindingInfoOffset());
-       memcpy(&buffer[1], &offset, 4); 
-}
-
-
-template <>
-FastStubHelperAtom<x86>::FastStubHelperAtom(Writer<x86>& writer, ObjectFile::Atom& target, 
-                                                                                                                       class LazyPointerAtom<x86>& lazyPointer, bool forLazyDylib)
-       : StubHelperAtom<x86>(writer, target, lazyPointer, forLazyDylib)
-{
-       if ( fgHelperHelperAtom == NULL ) {
-               fgHelperHelperAtom = new FastStubHelperHelperAtom<x86>::FastStubHelperHelperAtom(fWriter);
-               fWriter.fAllSynthesizedStubHelpers.push_back(fgHelperHelperAtom);
-       }
-       fReferences.push_back(new WriterReference<x86>(6, x86::kPCRel32, fgHelperHelperAtom));
-}
-
-
-template <>
-uint64_t FastStubHelperAtom<x86>::getSize() const
-{
-       return 10;
-}
-
-template <>
-void FastStubHelperAtom<x86>::copyRawContent(uint8_t buffer[]) const
-{
-       buffer[0]  = 0x68;              // pushl $lazy-info-offset
-       buffer[1]  = 0x00;
-       buffer[2]  = 0x00;
-       buffer[3]  = 0x00;
-       buffer[4]  = 0x00;
-       buffer[5]  = 0xE9;              // jmp helperhelper
-       buffer[6]  = 0x00;
-       buffer[7]  = 0x00;
-       buffer[8]  = 0x00;
-       buffer[9]  = 0x00;
-       
-       // the lazy binding info is created later than this helper atom, so there
-       // is no Reference to update.  Instead we blast the offset here.
-       uint32_t offset;
-       LittleEndian::set32(offset, fLazyPointerAtom.getLazyBindingInfoOffset());
-       memcpy(&buffer[1], &offset, 4);
-}
-
-template <typename A>
-const char* LazyPointerAtom<A>::getSectionName() const
-{
-       if ( fCloseStub )
-               return "__lazy_symbol";
-       else if ( fForLazyDylib )
-               return "__ld_symbol_ptr";
-       else
-               return "__la_symbol_ptr"; 
-}
-
-// specialize lazy pointer for x86_64 to initially pointer to stub helper
-template <>
-LazyPointerAtom<x86_64>::LazyPointerAtom(Writer<x86_64>& writer, ObjectFile::Atom& target, StubAtom<x86_64>& stub, bool forLazyDylib)
- : WriterAtom<x86_64>(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target), 
-       fExternalTarget(*stub.getTarget()), fForLazyDylib(forLazyDylib), fCloseStub(false), fLazyBindingOffset(0)
-{
-       if ( forLazyDylib ) 
-               writer.fAllSynthesizedLazyDylibPointers.push_back(this);
-       else
-               writer.fAllSynthesizedLazyPointers.push_back(this);
-
-       ObjectFile::Atom* helper;
-       if ( writer.fOptions.makeCompressedDyldInfo() && !forLazyDylib ) {
-               if ( writer.fOptions.makeClassicDyldInfo() ) 
-                       // hybrid LINKEDIT, no fast bind info for weak symbols so use traditional helper
-                       if ( writer.targetRequiresWeakBinding(target) )
-                               helper = new ClassicStubHelperAtom<x86_64>(writer, target, *this, forLazyDylib);
-                       else
-                               helper = new HybridStubHelperAtom<x86_64>(writer, target, *this, forLazyDylib);
-               else {
-                       if ( target.getDefinitionKind() == ObjectFile::Atom::kWeakDefinition ) 
-                               helper = &target;
-                       else
-                               helper = new FastStubHelperAtom<x86_64>(writer, target, *this, forLazyDylib);
-               }
-       }
-       else {
-               helper = new ClassicStubHelperAtom<x86_64>(writer, target, *this, forLazyDylib);
-       }
-       fReferences.push_back(new WriterReference<x86_64>(0, x86_64::kPointer, helper));
-}
-
-
-// specialize lazy pointer for x86 to initially pointer to stub helper
-template <>
-LazyPointerAtom<x86>::LazyPointerAtom(Writer<x86>& writer, ObjectFile::Atom& target, StubAtom<x86>& stub, bool forLazyDylib)
- : WriterAtom<x86>(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target), 
-       fExternalTarget(*stub.getTarget()), fForLazyDylib(forLazyDylib), fCloseStub(false), fLazyBindingOffset(0)
-{
-       if ( forLazyDylib ) 
-               writer.fAllSynthesizedLazyDylibPointers.push_back(this);
-       else
-               writer.fAllSynthesizedLazyPointers.push_back(this);
-
-       ObjectFile::Atom* helper;
-       if ( writer.fOptions.makeCompressedDyldInfo() && !forLazyDylib ) {
-               if ( writer.fOptions.makeClassicDyldInfo() ) {
-                       // hybrid LINKEDIT, no fast bind info for weak symbols so use traditional helper
-                       if ( writer.targetRequiresWeakBinding(target) )
-                               helper = new ClassicStubHelperAtom<x86>(writer, target, *this, forLazyDylib);
-                       else
-                               helper = new HybridStubHelperAtom<x86>(writer, target, *this, forLazyDylib);
-               }
-               else {
-                       if ( target.getDefinitionKind() == ObjectFile::Atom::kWeakDefinition ) 
-                               helper = &target;
-                       else
-                               helper = new FastStubHelperAtom<x86>(writer, target, *this, forLazyDylib);
-               }
-       }
-       else {
-               helper = new ClassicStubHelperAtom<x86>(writer, target, *this, forLazyDylib);
-       }
-       fReferences.push_back(new WriterReference<x86>(0, x86::kPointer, helper));
-}
-
-// specialize lazy pointer for arm to initially pointer to stub helper
-template <>
-LazyPointerAtom<arm>::LazyPointerAtom(Writer<arm>& writer, ObjectFile::Atom& target, StubAtom<arm>& stub, bool forLazyDylib)
- : WriterAtom<arm>(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target), 
-       fExternalTarget(*stub.getTarget()), fForLazyDylib(forLazyDylib), fCloseStub(false), fLazyBindingOffset(0)
-{
-       if ( forLazyDylib ) 
-               writer.fAllSynthesizedLazyDylibPointers.push_back(this);
-       else
-               writer.fAllSynthesizedLazyPointers.push_back(this);
-
-       // The one instruction stubs must be close to the lazy pointers
-       if ( stub.fKind == StubAtom<arm>::kStubShort )
-               fCloseStub = true;
-
-       ObjectFile::Atom* helper;
-       if ( forLazyDylib ) {
-               if ( writer.fDyldLazyDylibHelper == NULL )
-                       throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
-               helper = writer.fDyldLazyDylibHelper;
-       }
-       else if ( writer.fOptions.makeCompressedDyldInfo() ) {
-               if ( target.getDefinitionKind() == ObjectFile::Atom::kWeakDefinition ) 
-                       helper = &target;
-               else
-                       helper = new FastStubHelperAtom<arm>(writer, target, *this, forLazyDylib);
-       }
-       else {
-               if ( writer.fDyldClassicHelperAtom == NULL )
-                       throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
-               helper = writer.fDyldClassicHelperAtom;
-       }
-       fReferences.push_back(new WriterReference<arm>(0, arm::kPointer, helper));
-}
-
-template <typename A>
-LazyPointerAtom<A>::LazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target, StubAtom<A>& stub, bool forLazyDylib)
- : WriterAtom<A>(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target), 
-       fExternalTarget(*stub.getTarget()), fForLazyDylib(forLazyDylib), fCloseStub(false), fLazyBindingOffset(0)
-{
-       if ( forLazyDylib ) 
-               writer.fAllSynthesizedLazyDylibPointers.push_back(this);
-       else
-               writer.fAllSynthesizedLazyPointers.push_back(this);
-
-       fReferences.push_back(new WriterReference<A>(0, A::kPointer, &target));
-}
-
-
-
-template <typename A>
-const char* LazyPointerAtom<A>::lazyPointerName(const char* name)
-{
-       char* buf;
-       asprintf(&buf, "%s$lazy_pointer", name);
-       return buf;
-}
-
-template <typename A>
-void LazyPointerAtom<A>::copyRawContent(uint8_t buffer[]) const
-{
-       bzero(buffer, getSize());
-}
-
-
-template <typename A>
-NonLazyPointerAtom<A>::NonLazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target)
- : WriterAtom<A>(writer, Segment::fgDataSegment), fName(nonlazyPointerName(target.getName())), fTarget(&target)
-{
-       writer.fAllSynthesizedNonLazyPointers.push_back(this);
-       fReferences.push_back(new WriterReference<A>(0, A::kPointer, &target));
-}
-
-template <typename A>
-NonLazyPointerAtom<A>::NonLazyPointerAtom(Writer<A>& writer)
- : WriterAtom<A>(writer, Segment::fgDataSegment), fName("none"), fTarget(NULL)
-{
-       writer.fAllSynthesizedNonLazyPointers.push_back(this);
-}
-
-template <typename A>
-NonLazyPointerAtom<A>::NonLazyPointerAtom(Writer<A>& writer, const char* targetName)
- : WriterAtom<A>(writer, Segment::fgDataSegment), fName(nonlazyPointerName(targetName)), fTarget(NULL)
-{
-       writer.fAllSynthesizedNonLazyPointers.push_back(this);
-       fReferences.push_back(new WriterReference<A>(0, A::kPointer, targetName));
-}
-
-template <typename A>
-const char* NonLazyPointerAtom<A>::nonlazyPointerName(const char* name)
-{
-       char* buf;
-       asprintf(&buf, "%s$non_lazy_pointer", name);
-       return buf;
-}
-
-template <typename A>
-void NonLazyPointerAtom<A>::copyRawContent(uint8_t buffer[]) const
-{
-       bzero(buffer, getSize());
-}
-
-
-
-
-template <>
-ObjectFile::Alignment StubAtom<ppc>::getAlignment() const
-{
-       return 2;
-}
-
-template <>
-ObjectFile::Alignment StubAtom<ppc64>::getAlignment() const
-{
-       return 2;
-}
-
-template <>
-ObjectFile::Alignment StubAtom<arm>::getAlignment() const
-{
-       return 2;
-}
-
-template <>
-StubAtom<ppc>::StubAtom(Writer<ppc>& writer, ObjectFile::Atom& target, bool forLazyDylib)
- : WriterAtom<ppc>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), 
-       fTarget(target), fForLazyDylib(forLazyDylib)
-{
-       writer.fAllSynthesizedStubs.push_back(this);
-       LazyPointerAtom<ppc>* lp;
-       if (  fWriter.fOptions.prebind() ) {
-               // for prebound ppc, lazy pointer starts out pointing to target symbol's address
-               // if target is a weak definition within this linkage unit or zero if in some dylib
-               lp = new LazyPointerAtom<ppc>(writer, target, *this, forLazyDylib);
-       }
-       else {
-               // for non-prebound ppc, lazy pointer starts out pointing to dyld_stub_binding_helper glue code
-               if ( forLazyDylib ) {
-                       if ( writer.fDyldLazyDylibHelper == NULL )
-                               throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
-                       lp = new LazyPointerAtom<ppc>(writer, *writer.fDyldLazyDylibHelper, *this, forLazyDylib);
-               }
-               else {
-                       if ( writer.fDyldClassicHelperAtom == NULL )
-                               throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
-                       lp = new LazyPointerAtom<ppc>(writer, *writer.fDyldClassicHelperAtom, *this, forLazyDylib);
-               }
-       }
-       fKind = ( fWriter.fSlideable ? kStubPIC : kStubNoPIC );
-       if ( fKind == kStubPIC ) {
-               // picbase is 8 bytes into atom
-               fReferences.push_back(new WriterReference<ppc>(12, ppc::kPICBaseHigh16, lp, 0, this, 8));
-               fReferences.push_back(new WriterReference<ppc>(20, ppc::kPICBaseLow16, lp, 0, this, 8));
-       }
-       else {
-               fReferences.push_back(new WriterReference<ppc>(0, ppc::kAbsHigh16AddLow, lp));
-               fReferences.push_back(new WriterReference<ppc>(4, ppc::kAbsLow16, lp));
-       }
-}
-
-template <>
-StubAtom<ppc64>::StubAtom(Writer<ppc64>& writer, ObjectFile::Atom& target, bool forLazyDylib)
- : WriterAtom<ppc64>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), 
-       fTarget(target), fForLazyDylib(forLazyDylib)
-{
-       writer.fAllSynthesizedStubs.push_back(this);
-
-       LazyPointerAtom<ppc64>* lp;
-       if ( forLazyDylib ) {
-               if ( writer.fDyldLazyDylibHelper == NULL )
-                       throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
-               lp = new LazyPointerAtom<ppc64>(writer, *writer.fDyldLazyDylibHelper, *this, forLazyDylib);
-       }
-       else {
-               if ( writer.fDyldClassicHelperAtom == NULL )
-                       throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
-               lp = new LazyPointerAtom<ppc64>(writer, *writer.fDyldClassicHelperAtom, *this, forLazyDylib);
-       }
-       if ( fWriter.fSlideable || ((fWriter.fPageZeroAtom != NULL) && (fWriter.fPageZeroAtom->getSize() > 4096)) )
-               fKind = kStubPIC;
-       else
-               fKind = kStubNoPIC;
-       if ( fKind == kStubPIC ) {
-               // picbase is 8 bytes into atom
-               fReferences.push_back(new WriterReference<ppc64>(12, ppc64::kPICBaseHigh16, lp, 0, this, 8));
-               fReferences.push_back(new WriterReference<ppc64>(20, ppc64::kPICBaseLow14, lp, 0, this, 8));
-       }
-       else {
-               fReferences.push_back(new WriterReference<ppc64>(0, ppc64::kAbsHigh16AddLow, lp));
-               fReferences.push_back(new WriterReference<ppc64>(4, ppc64::kAbsLow14, lp));
-       }
-}
-
-template <>
-StubAtom<x86>::StubAtom(Writer<x86>& writer, ObjectFile::Atom& target, bool forLazyDylib)
- : WriterAtom<x86>(writer, (writer.fOptions.makeCompressedDyldInfo()|| forLazyDylib) ? Segment::fgTextSegment : Segment::fgImportSegment),
-                                       fName(NULL), fTarget(target), fForLazyDylib(forLazyDylib)
-{
-       if ( writer.fOptions.makeCompressedDyldInfo() || forLazyDylib ) {
-               fKind = kStubNoPIC;
-               fName = stubName(target.getName());
-               LazyPointerAtom<x86>* lp = new LazyPointerAtom<x86>(writer, target, *this, forLazyDylib);
-               fReferences.push_back(new WriterReference<x86>(2, x86::kAbsolute32, lp));
-               writer.fAllSynthesizedStubs.push_back(this);
-       }
-       else {
-               fKind = kJumpTable;
-               if ( &target == NULL ) 
-                       asprintf((char**)&fName, "cache-line-crossing-stub %p", this);
-               else {
-                       fName = stubName(target.getName());
-                       writer.fAllSynthesizedStubs.push_back(this);
-               }
-       }
-}
-
-
-template <>
-StubAtom<x86_64>::StubAtom(Writer<x86_64>& writer, ObjectFile::Atom& target, bool forLazyDylib)
- : WriterAtom<x86_64>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
-{
-       writer.fAllSynthesizedStubs.push_back(this);
-
-       LazyPointerAtom<x86_64>* lp = new LazyPointerAtom<x86_64>(writer, target, *this, forLazyDylib);
-       fReferences.push_back(new WriterReference<x86_64>(2, x86_64::kPCRel32, lp));
-}
-
-template <>
-StubAtom<arm>::StubAtom(Writer<arm>& writer, ObjectFile::Atom& target, bool forLazyDylib)
- : WriterAtom<arm>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
-{
-       writer.fAllSynthesizedStubs.push_back(this);
-       if ( (writer.fDylibSymbolCountUpperBound < 900) 
-               && writer.fOptions.makeCompressedDyldInfo() 
-               && (writer.fOptions.outputKind() != Options::kDynamicLibrary) 
-               && !forLazyDylib ) {
-               // dylibs might have __TEXT and __DATA pulled apart to live in shared region
-               // if > 1000 stubs, the displacement to the lazy pointer my be > 12 bits.
-               fKind = kStubShort;
-       }
-       else if ( fWriter.fSlideable ) {
-               fKind = kStubPIC;
-       }
-       else {
-               fKind = kStubNoPIC;
-       }
-       LazyPointerAtom<arm>* lp = new LazyPointerAtom<arm>(writer, target, *this, forLazyDylib);
-       switch ( fKind ) {
-               case kStubPIC:
-                       fReferences.push_back(new WriterReference<arm>(12, arm::kPointerDiff, lp, 0, this, 12));
-                       break;
-               case kStubNoPIC:
-                       fReferences.push_back(new WriterReference<arm>(8, arm::kReadOnlyPointer, lp));
-                       break;
-               case kStubShort:
-                       fReferences.push_back(new WriterReference<arm>(0, arm::kPointerDiff12, lp, 0, this, 8));
-                       break;
-               default:
-                       throw "internal error";
-       }
-}
-
-
-template <typename A>
-const char* StubAtom<A>::stubName(const char* name)
-{
-       char* buf;
-       asprintf(&buf, "%s$stub", name);
-       return buf;
-}
-
-template <>
-uint64_t StubAtom<ppc>::getSize() const
-{
-
-       return ( (fKind == kStubPIC) ? 32 : 16 );
-}
-
-template <>
-uint64_t StubAtom<ppc64>::getSize() const
-{
-       return ( (fKind == kStubPIC)  ? 32 : 16 );
-}
-
-
-template <>
-uint64_t StubAtom<arm>::getSize() const
-{
-       switch ( fKind ) {
-               case kStubPIC:
-                       return 16;
-               case kStubNoPIC:
-                       return 12;
-               case kStubShort:
-                       return 4;
-               default:
-                       throw "internal error";
-       }
-}
-
-template <>
-uint64_t StubAtom<x86>::getSize() const
-{
-       switch ( fKind ) {
-               case kStubNoPIC:
-                       return 6;
-               case kJumpTable:
-                       return 5;
-               default:
-                       throw "internal error";
-       }
-}
-
-template <>
-uint64_t StubAtom<x86_64>::getSize() const
-{
-       return 6;
-}
-
-template <>
-ObjectFile::Alignment StubAtom<x86>::getAlignment() const
-{
-       switch ( fKind ) {
-               case kStubNoPIC:
-                       return 1;
-               case kJumpTable:
-                       return 0; // special case x86 self-modifying stubs to be byte aligned
-               default:
-                       throw "internal error";
-       }
-}
-
-template <>
-void StubAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
-{
-       if ( fKind == kStubPIC ) {
-               OSWriteBigInt32(&buffer [0], 0, 0x7c0802a6);    //      mflr r0
-               OSWriteBigInt32(&buffer[ 4], 0, 0x429f0005);    //  bcl 20,31,Lpicbase
-               OSWriteBigInt32(&buffer[ 8], 0, 0x7d6802a6);    // Lpicbase: mflr r11
-               OSWriteBigInt32(&buffer[12], 0, 0x3d6b0000);    //      addis r11,r11,ha16(L_fwrite$lazy_ptr-Lpicbase)
-               OSWriteBigInt32(&buffer[16], 0, 0x7c0803a6);    //      mtlr r0
-               OSWriteBigInt32(&buffer[20], 0, 0xe98b0001);    //      ldu r12,lo16(L_fwrite$lazy_ptr-Lpicbase)(r11)
-               OSWriteBigInt32(&buffer[24], 0, 0x7d8903a6);    //  mtctr r12
-               OSWriteBigInt32(&buffer[28], 0, 0x4e800420);    //  bctr
-       }
-       else {
-               OSWriteBigInt32(&buffer[ 0], 0, 0x3d600000);    // lis r11,ha16(L_fwrite$lazy_ptr)
-               OSWriteBigInt32(&buffer[ 4], 0, 0xe98b0001);    // ldu r12,lo16(L_fwrite$lazy_ptr)(r11)
-               OSWriteBigInt32(&buffer[ 8], 0, 0x7d8903a6);    // mtctr r12
-               OSWriteBigInt32(&buffer[12], 0, 0x4e800420);    // bctr
-       }
-}
-
-template <>
-void StubAtom<ppc>::copyRawContent(uint8_t buffer[]) const
-{
-       if ( fKind == kStubPIC ) {
-               OSWriteBigInt32(&buffer[ 0], 0, 0x7c0802a6);    //      mflr r0
-               OSWriteBigInt32(&buffer[ 4], 0, 0x429f0005);    //  bcl 20,31,Lpicbase
-               OSWriteBigInt32(&buffer[ 8], 0, 0x7d6802a6);    // Lpicbase: mflr r11
-               OSWriteBigInt32(&buffer[12], 0, 0x3d6b0000);    //      addis r11,r11,ha16(L_fwrite$lazy_ptr-Lpicbase)
-               OSWriteBigInt32(&buffer[16], 0, 0x7c0803a6);    //      mtlr r0
-               OSWriteBigInt32(&buffer[20], 0, 0x858b0000);    //      lwzu r12,lo16(L_fwrite$lazy_ptr-Lpicbase)(r11)
-               OSWriteBigInt32(&buffer[24], 0, 0x7d8903a6);    //  mtctr r12
-               OSWriteBigInt32(&buffer[28], 0, 0x4e800420);    //  bctr
-       }
-       else {
-               OSWriteBigInt32(&buffer[ 0], 0, 0x3d600000);    // lis r11,ha16(L_fwrite$lazy_ptr)
-               OSWriteBigInt32(&buffer[ 4], 0, 0x858b0000);    // lwzu r12,lo16(L_fwrite$lazy_ptr)(r11)
-               OSWriteBigInt32(&buffer[ 8], 0, 0x7d8903a6);    // mtctr r12
-               OSWriteBigInt32(&buffer[12], 0, 0x4e800420);    // bctr
-       }
-}
-
-template <>
-void StubAtom<x86>::copyRawContent(uint8_t buffer[]) const
-{
-       switch ( fKind ) {
-               case kStubNoPIC:
-                       buffer[0] = 0xFF;               // jmp *foo$lazy_pointer
-                       buffer[1] = 0x25;
-                       buffer[2] = 0x00;
-                       buffer[3] = 0x00;
-                       buffer[4] = 0x00;
-                       buffer[5] = 0x00;
-                       break;
-               case kJumpTable:
-                       if ( fWriter.fOptions.prebind() ) {
-                               uint32_t address = this->getAddress();
-                               int32_t rel32 = 0 - (address+5); 
-                               buffer[0] = 0xE9;
-                               buffer[1] = rel32 & 0xFF;
-                               buffer[2] = (rel32 >> 8) & 0xFF;
-                               buffer[3] = (rel32 >> 16) & 0xFF;
-                               buffer[4] = (rel32 >> 24) & 0xFF;
-                       }
-                       else {
-                               buffer[0] = 0xF4;
-                               buffer[1] = 0xF4;
-                               buffer[2] = 0xF4;
-                               buffer[3] = 0xF4;
-                               buffer[4] = 0xF4;
-                       }
-                       break;
-               default:
-                       throw "internal error";
-       }
-}
-
-template <>
-void StubAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
-{
-       buffer[0] = 0xFF;               // jmp *foo$lazy_pointer(%rip)
-       buffer[1] = 0x25;
-       buffer[2] = 0x00;
-       buffer[3] = 0x00;
-       buffer[4] = 0x00;
-       buffer[5] = 0x00;
-}
-
-template <>
-void StubAtom<arm>::copyRawContent(uint8_t buffer[]) const
-{
-       switch ( fKind ) {
-               case kStubPIC:
-                       OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc004); //      ldr ip, pc + 12
-                       OSWriteLittleInt32(&buffer[ 4], 0, 0xe08fc00c); //      add ip, pc, ip
-                       OSWriteLittleInt32(&buffer[ 8], 0, 0xe59cf000); //      ldr pc, [ip]
-                       OSWriteLittleInt32(&buffer[12], 0, 0x00000000); //      .long L_foo$lazy_ptr - (L1$scv + 8)
-                       break;
-               case kStubNoPIC:
-                       OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc000); //      ldr ip, [pc, #0]
-                       OSWriteLittleInt32(&buffer[ 4], 0, 0xe59cf000); //      ldr pc, [ip]
-                       OSWriteLittleInt32(&buffer[ 8], 0, 0x00000000); //      .long   L_foo$lazy_ptr
-                       break;
-               case kStubShort:
-                       OSWriteLittleInt32(&buffer[ 0], 0, 0xE59FF000);//       ldr     pc, [pc, #foo$lazy_ptr]
-                       break;
-               default:
-                       throw "internal error";
-       }
-}
-
-// x86_64 stubs are 6 bytes 
-template <>
-ObjectFile::Alignment StubAtom<x86_64>::getAlignment() const
-{
-       return 1;
-}
-
-template <>
-const char*    StubAtom<ppc>::getSectionName() const
-{
-       return ( (fKind == kStubPIC) ? "__picsymbolstub1" : "__symbol_stub1");
-}
-
-template <>
-const char*    StubAtom<ppc64>::getSectionName() const
-{
-       return ( (fKind == kStubPIC) ? "__picsymbolstub1" : "__symbol_stub1");
-}
-
-template <>
-const char*    StubAtom<arm>::getSectionName() const
-{
-       switch ( fKind ) {
-               case kStubPIC:
-                       return "__picsymbolstub4";
-               case kStubNoPIC:
-                       return "__symbol_stub4";
-               case kStubShort:
-                       return "__symbolstub1";
-               default:
-                       throw "internal error";
-       }
-}
-
-template <>
-const char*    StubAtom<x86>::getSectionName() const
-{
-       switch ( fKind ) {
-               case kStubNoPIC:
-                       return "__symbol_stub";
-               case kJumpTable:
-                       return "__jump_table";
-               default:
-                       throw "internal error";
-       }
-}
-
-
-
-
-struct AtomByNameSorter
-{
-     bool operator()(ObjectFile::Atom* left, ObjectFile::Atom* right)
-     {
-          return (strcmp(left->getName(), right->getName()) < 0);
-     }
-};
-
-template <typename P>
-struct ExternalRelocSorter
-{
-     bool operator()(const macho_relocation_info<P>& left, const macho_relocation_info<P>& right)
-     {
-               // sort first by symbol number
-               if ( left.r_symbolnum() != right.r_symbolnum() )
-                       return (left.r_symbolnum() < right.r_symbolnum());
-               // then sort all uses of the same symbol by address
-               return (left.r_address() < right.r_address());
-     }
-};
-
-
-template <typename A>
-Writer<A>::Writer(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries)
-       : ExecutableFile::Writer(dynamicLibraries), fFilePath(strdup(path)), fOptions(options), 
-         fAllAtoms(NULL), fStabs(NULL), fRegularDefAtomsThatOverrideADylibsWeakDef(NULL), fLoadCommandsSection(NULL),
-         fLoadCommandsSegment(NULL), fMachHeaderAtom(NULL), fEncryptionLoadCommand(NULL), fSegmentCommands(NULL), 
-         fSymbolTableCommands(NULL), fHeaderPadding(NULL), fUnwindInfoAtom(NULL),
-         fUUIDAtom(NULL), fPadSegmentInfo(NULL), fEntryPoint( NULL), 
-         fDyldClassicHelperAtom(NULL), fDyldCompressedHelperAtom(NULL), fDyldLazyDylibHelper(NULL),
-         fSectionRelocationsAtom(NULL),   fCompressedRebaseInfoAtom(NULL),  fCompressedBindingInfoAtom(NULL),
-         fCompressedWeakBindingInfoAtom(NULL), fCompressedLazyBindingInfoAtom(NULL), fCompressedExportInfoAtom(NULL),
-         fLocalRelocationsAtom(NULL), fExternalRelocationsAtom(NULL),
-         fSymbolTableAtom(NULL), fSplitCodeToDataContentAtom(NULL), fIndirectTableAtom(NULL), fModuleInfoAtom(NULL), 
-         fStringsAtom(NULL), fPageZeroAtom(NULL), fFastStubGOTAtom(NULL), fSymbolTable(NULL), fSymbolTableCount(0), 
-         fSymbolTableStabsCount(0), fSymbolTableLocalCount(0), fSymbolTableExportCount(0), fSymbolTableImportCount(0), 
-         fLargestAtomSize(1), 
-         fEmitVirtualSections(false), fHasWeakExports(false), fReferencesWeakImports(false), 
-         fCanScatter(false), fWritableSegmentPastFirst4GB(false), fNoReExportedDylibs(false), 
-         fBiggerThanTwoGigs(false), fSlideable(false), fHasThumbBranches(false), 
-         fFirstWritableSegment(NULL), fAnonNameIndex(1000)
-{
-       switch ( fOptions.outputKind() ) {
-               case Options::kDynamicExecutable:
-               case Options::kStaticExecutable:
-                       if ( fOptions.zeroPageSize() != 0 )
-                               fWriterSynthesizedAtoms.push_back(fPageZeroAtom = new PageZeroAtom<A>(*this));
-                       if ( fOptions.outputKind() == Options::kDynamicExecutable )
-                               fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(fMachHeaderAtom = new MachHeaderAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
-                       if ( fOptions.makeCompressedDyldInfo() ) 
-                               fWriterSynthesizedAtoms.push_back(new DyldInfoLoadCommandsAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
-                       if ( fOptions.outputKind() == Options::kDynamicExecutable )
-                               fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom<A>(*this));
-                       if ( fOptions.hasCustomStack() )
-                               fWriterSynthesizedAtoms.push_back(new CustomStackAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(new MinimalTextAtom<A>(*this));
-                       if ( fOptions.needsUnwindInfoSection() )
-                               fWriterSynthesizedAtoms.push_back(fUnwindInfoAtom = new UnwindInfoAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
-                       if ( fOptions.makeCompressedDyldInfo() ) {
-                               fWriterSynthesizedAtoms.push_back(fCompressedRebaseInfoAtom = new CompressedRebaseInfoLinkEditAtom<A>(*this));
-                               fWriterSynthesizedAtoms.push_back(fCompressedBindingInfoAtom = new CompressedBindingInfoLinkEditAtom<A>(*this));
-                               fWriterSynthesizedAtoms.push_back(fCompressedWeakBindingInfoAtom = new CompressedWeakBindingInfoLinkEditAtom<A>(*this));
-                               fWriterSynthesizedAtoms.push_back(fCompressedLazyBindingInfoAtom = new CompressedLazyBindingInfoLinkEditAtom<A>(*this));
-                               fWriterSynthesizedAtoms.push_back(fCompressedExportInfoAtom = new CompressedExportInfoLinkEditAtom<A>(*this));
-                       }
-                       if ( fOptions.makeClassicDyldInfo() ) 
-                               fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
-                       if ( fOptions.makeClassicDyldInfo() ) 
-                               fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
-                       break;
-               case Options::kPreload:
-                       fWriterSynthesizedAtoms.push_back(fMachHeaderAtom = new MachHeaderAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
-                       break;
-               case Options::kDynamicLibrary:
-               case Options::kDynamicBundle:
-                       fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
-               case Options::kKextBundle:
-                       fWriterSynthesizedAtoms.push_back(fMachHeaderAtom = new MachHeaderAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
-                       if ( fOptions.outputKind() == Options::kDynamicLibrary ) {
-                               fWriterSynthesizedAtoms.push_back(new DylibIDLoadCommandsAtom<A>(*this));
-                               if ( fOptions.initFunctionName() != NULL )
-                                       fWriterSynthesizedAtoms.push_back(new RoutinesLoadCommandsAtom<A>(*this));
-                       }
-                       fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
-                       if ( fOptions.makeCompressedDyldInfo() )
-                               fWriterSynthesizedAtoms.push_back(new DyldInfoLoadCommandsAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
-                       if ( fOptions.sharedRegionEligible() )
-                               fWriterSynthesizedAtoms.push_back(new SegmentSplitInfoLoadCommandsAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(new MinimalTextAtom<A>(*this));
-                       if ( fOptions.needsUnwindInfoSection() )
-                               fWriterSynthesizedAtoms.push_back(fUnwindInfoAtom = new UnwindInfoAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
-                       if ( fOptions.makeCompressedDyldInfo() ) {
-                               fWriterSynthesizedAtoms.push_back(fCompressedRebaseInfoAtom = new CompressedRebaseInfoLinkEditAtom<A>(*this));
-                               fWriterSynthesizedAtoms.push_back(fCompressedBindingInfoAtom = new CompressedBindingInfoLinkEditAtom<A>(*this));
-                               fWriterSynthesizedAtoms.push_back(fCompressedWeakBindingInfoAtom = new CompressedWeakBindingInfoLinkEditAtom<A>(*this));
-                               fWriterSynthesizedAtoms.push_back(fCompressedLazyBindingInfoAtom = new CompressedLazyBindingInfoLinkEditAtom<A>(*this));
-                               fWriterSynthesizedAtoms.push_back(fCompressedExportInfoAtom = new CompressedExportInfoLinkEditAtom<A>(*this));
-                       }
-                       if ( fOptions.makeClassicDyldInfo() ) 
-                               fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
-                       if ( fOptions.sharedRegionEligible() ) {
-                               fWriterSynthesizedAtoms.push_back(fSplitCodeToDataContentAtom = new SegmentSplitInfoContentAtom<A>(*this));
-                       }
-                       fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
-                       if ( fOptions.makeClassicDyldInfo() ) 
-                               fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
-                       if ( fOptions.outputKind() != Options::kKextBundle ) 
-                               fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
-                       if ( this->needsModuleTable() )
-                               fWriterSynthesizedAtoms.push_back(fModuleInfoAtom = new ModuleInfoLinkEditAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
-                       break;
-               case Options::kObjectFile:
-                       fWriterSynthesizedAtoms.push_back(fMachHeaderAtom = new MachHeaderAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
-                       break;
-               case Options::kDyld:
-                       fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(fMachHeaderAtom = new MachHeaderAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
-                       if ( fOptions.needsUnwindInfoSection() )
-                               fWriterSynthesizedAtoms.push_back(fUnwindInfoAtom = new UnwindInfoAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
-                       fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
-                       break;
-       }
-
-       // add extra commmands
-       bool hasReExports = false;
-       uint32_t ordinal = 1;
-       switch ( fOptions.outputKind() ) {
-               case Options::kDynamicExecutable:
-                       if ( fOptions.makeEncryptable() ) {
-                               fEncryptionLoadCommand = new EncryptionLoadCommandsAtom<A>(*this);
-                               fWriterSynthesizedAtoms.push_back(fEncryptionLoadCommand);
-                       }
-                       // fall through
-               case Options::kDynamicLibrary:
-               case Options::kDynamicBundle:
-                       {
-                               // add dylib load command atoms for all dynamic libraries
-                               const unsigned int libCount = dynamicLibraries.size();
-                               for (unsigned int i=0; i < libCount; ++i) {
-                                       ExecutableFile::DyLibUsed& dylibInfo = dynamicLibraries[i];
-                                       //fprintf(stderr, "dynamicLibraries[%d]: reader=%p, %s, install=%s\n", i, dylibInfo.reader, dylibInfo.reader->getPath(), dylibInfo.reader->getInstallPath() );
-                                       
-                                       if ( dylibInfo.options.fReExport ) {
-                                               hasReExports = true;
-                                       }
-                                       else {
-                                               const char* parentUmbrella = dylibInfo.reader->parentUmbrella();
-                                               if ( (parentUmbrella != NULL) && (fOptions.outputKind() == Options::kDynamicLibrary) ) {
-                                                       const char* thisIDLastSlash = strrchr(fOptions.installPath(), '/');
-                                                       if ( (thisIDLastSlash != NULL) && (strcmp(&thisIDLastSlash[1], parentUmbrella) == 0) )
-                                                               hasReExports = true;
-                                               }
-                                       }
-                               
-                                       if ( dylibInfo.options.fWeakImport ) {
-                                               fForcedWeakImportReaders.insert(dylibInfo.reader);
-                                       }
-
-                                       if ( dylibInfo.options.fBundleLoader ) {
-                                               fLibraryToOrdinal[dylibInfo.reader] = EXECUTABLE_ORDINAL;
-                                       }
-                                       else {
-                                               // see if a DylibLoadCommandsAtom has already been created for this install path
-                                               bool newDylib = true;
-                                               const char* dylibInstallPath = dylibInfo.reader->getInstallPath();
-                                               for (unsigned int seenLib=0; seenLib < i; ++seenLib) {
-                                                       ExecutableFile::DyLibUsed& seenDylibInfo = dynamicLibraries[seenLib];
-                                                       if ( !seenDylibInfo.options.fBundleLoader ) {
-                                                               const char* seenDylibInstallPath = seenDylibInfo.reader->getInstallPath();
-                                                               if ( strcmp(seenDylibInstallPath, dylibInstallPath) == 0 ) {
-                                                                       fLibraryToOrdinal[dylibInfo.reader] = fLibraryToOrdinal[seenDylibInfo.reader];
-                                                                       fLibraryToLoadCommand[dylibInfo.reader] = fLibraryToLoadCommand[seenDylibInfo.reader]; 
-                                                                       fLibraryAliases[dylibInfo.reader] = seenDylibInfo.reader;
-                                                                       newDylib = false;
-                                                                       break;
-                                                               }
-                                                       }
-                                               }
-
-                                               if ( newDylib ) {
-                                                       // assign new ordinal and check for other paired load commands
-                                                       fLibraryToOrdinal[dylibInfo.reader] = ordinal++;
-                                                       DylibLoadCommandsAtom<A>* dyliblc = new DylibLoadCommandsAtom<A>(*this, dylibInfo);
-                                                       fLibraryToLoadCommand[dylibInfo.reader] = dyliblc;
-                                                       fWriterSynthesizedAtoms.push_back(dyliblc);
-                                                       if ( dylibInfo.options.fReExport 
-                                                               && !fOptions.useSimplifiedDylibReExports() 
-                                                               && (fOptions.outputKind() == Options::kDynamicLibrary) ) {
-                                                               // see if child has sub-framework that is this
-                                                               bool isSubFramework = false;
-                                                               const char* childInUmbrella = dylibInfo.reader->parentUmbrella();
-                                                               if ( childInUmbrella != NULL ) {
-                                                                       const char* myLeaf = strrchr(fOptions.installPath(), '/');
-                                                                       if ( myLeaf != NULL ) {
-                                                                               if ( strcmp(childInUmbrella, &myLeaf[1]) == 0 )
-                                                                                       isSubFramework = true;
-                                                                       }
-                                                               }
-                                                               // LC_SUB_FRAMEWORK is in child, so do nothing in parent 
-                                                               if ( ! isSubFramework ) {
-                                                                       // this dylib also needs a sub_x load command
-                                                                       bool isFrameworkReExport = false;
-                                                                       const char* lastSlash = strrchr(dylibInstallPath, '/');
-                                                                       if ( lastSlash != NULL ) {
-                                                                               char frameworkName[strlen(lastSlash)+20];
-                                                                               sprintf(frameworkName, "/%s.framework/", &lastSlash[1]);
-                                                                               isFrameworkReExport = (strstr(dylibInstallPath, frameworkName) != NULL);
-                                                                       }
-                                                                       if ( isFrameworkReExport ) {
-                                                                               // needs a LC_SUB_UMBRELLA command
-                                                                               fWriterSynthesizedAtoms.push_back(new SubUmbrellaLoadCommandsAtom<A>(*this, &lastSlash[1]));
-                                                                       }
-                                                                       else {
-                                                                               // needs a LC_SUB_LIBRARY command
-                                                                               const char* nameStart = &lastSlash[1];
-                                                                               if ( lastSlash == NULL )
-                                                                                       nameStart = dylibInstallPath;
-                                                                               int len = strlen(nameStart);
-                                                                               const char* dot = strchr(nameStart, '.');
-                                                                               if ( dot != NULL )
-                                                                                       len = dot - nameStart;
-                                                                               fWriterSynthesizedAtoms.push_back(new SubLibraryLoadCommandsAtom<A>(*this, nameStart, len));
-                                                                       }
-                                                               }
-                                                       }
-                                               }
-                                       }
-                               }
-                               // add umbrella command if needed
-                               if ( fOptions.umbrellaName() != NULL ) {
-                                       fWriterSynthesizedAtoms.push_back(new UmbrellaLoadCommandsAtom<A>(*this, fOptions.umbrellaName()));
-                               }
-                               // add allowable client commands if used
-                               std::vector<const char*>& allowableClients = fOptions.allowableClients();
-                               for (std::vector<const char*>::iterator it=allowableClients.begin(); it != allowableClients.end(); ++it)
-                                       fWriterSynthesizedAtoms.push_back(new AllowableClientLoadCommandsAtom<A>(*this, *it));
-                       }
-                       break;
-               case Options::kStaticExecutable:
-               case Options::kObjectFile:
-               case Options::kDyld:
-               case Options::kPreload:
-               case Options::kKextBundle:
-                       break;
-       }
-       fNoReExportedDylibs = !hasReExports;
-       
-       // add any rpath load commands
-       for(std::vector<const char*>::const_iterator it=fOptions.rpaths().begin(); it != fOptions.rpaths().end(); ++it) {
-               fWriterSynthesizedAtoms.push_back(new RPathLoadCommandsAtom<A>(*this, *it));
-       }
-       
-       // set up fSlideable
-       switch ( fOptions.outputKind() ) {
-               case Options::kObjectFile:
-               case Options::kStaticExecutable:
-                       fSlideable = false;
-                       break;
-               case Options::kDynamicExecutable:
-                       fSlideable = fOptions.positionIndependentExecutable();
-                       break;
-               case Options::kDyld:
-               case Options::kDynamicLibrary:
-               case Options::kDynamicBundle:
-               case Options::kPreload:
-               case Options::kKextBundle:
-                       fSlideable = true;
-                       break;
-       }
-       
-       //fprintf(stderr, "ordinals table:\n");
-       //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
-       //      fprintf(stderr, "%d <== %s\n", it->second, it->first->getPath());
-       //}
-}
-
-template <typename A>
-Writer<A>::~Writer()
-{
-       if ( fFilePath != NULL )
-               free((void*)fFilePath);
-       if ( fSymbolTable != NULL )
-               delete [] fSymbolTable;
-}
-
-
-// for ppc64, -mdynamic-no-pic only works in low 2GB, so we might need to split the zeropage into two segments
-template <>bool Writer<ppc64>::mightNeedPadSegment() { return (fOptions.zeroPageSize() >= 0x80000000ULL); }
-template <typename A> bool Writer<A>::mightNeedPadSegment() { return false; }
-
-
-template <typename A>
-ObjectFile::Atom* Writer<A>::getUndefinedProxyAtom(const char* name)
-{
-       if ( fOptions.outputKind() == Options::kKextBundle ) {
-               return new UndefinedSymbolProxyAtom<A>(*this, name);
-       }
-       else if ( fOptions.outputKind() == Options::kObjectFile ) {
-               // when doing -r -exported_symbols_list, don't create proxy for a symbol
-               // that is supposed to be exported.  We want an error instead
-               // <rdar://problem/5062685> ld does not report error when -r is used and exported symbols are not defined.
-               if ( fOptions.hasExportMaskList() && fOptions.shouldExport(name) )
-                       return NULL;
-               else
-                       return new UndefinedSymbolProxyAtom<A>(*this, name);
-       }
-       else if ( (fOptions.undefinedTreatment() != Options::kUndefinedError) || fOptions.allowedUndefined(name) )  
-               return new UndefinedSymbolProxyAtom<A>(*this, name);
-       else
-               return NULL;
-}
-
-template <typename A>
-uint8_t Writer<A>::ordinalForLibrary(ObjectFile::Reader* lib)
-{
-       // flat namespace images use zero for all ordinals
-       if (  fOptions.nameSpace() != Options::kTwoLevelNameSpace )
-               return 0;
-
-       // is an UndefinedSymbolProxyAtom
-       if ( lib == this )
-               if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace )
-                       return DYNAMIC_LOOKUP_ORDINAL;
-
-       std::map<class ObjectFile::Reader*, uint32_t>::iterator pos = fLibraryToOrdinal.find(lib);
-       if ( pos != fLibraryToOrdinal.end() )
-               return pos->second;
-
-       throw "can't find ordinal for imported symbol";
-}
-
-template <typename A>
-bool Writer<A>::targetRequiresWeakBinding(const ObjectFile::Atom& target)
-{
-       switch ( target.getDefinitionKind() ) {
-               case ObjectFile::Atom::kExternalWeakDefinition:
-               case ObjectFile::Atom::kWeakDefinition:
-                       return true;
-               case ObjectFile::Atom::kExternalDefinition:
-               case ObjectFile::Atom::kAbsoluteSymbol:
-               case ObjectFile::Atom::kRegularDefinition:
-               case ObjectFile::Atom::kTentativeDefinition:
-                       break;
-       }
-       return false;
-}
-
-template <typename A>
-int Writer<A>::compressedOrdinalForImortedAtom(ObjectFile::Atom* target)
-{
-       // flat namespace images use zero for all ordinals
-       if (  fOptions.nameSpace() != Options::kTwoLevelNameSpace )
-               return BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
-
-       // is an UndefinedSymbolProxyAtom
-       ObjectFile::Reader* lib = target->getFile();
-       if ( lib == this )
-               if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace )
-                       return BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
-
-       std::map<class ObjectFile::Reader*, uint32_t>::iterator pos;
-       switch ( target->getDefinitionKind() ) {
-               case ObjectFile::Atom::kExternalDefinition:
-               case ObjectFile::Atom::kExternalWeakDefinition:
-                       pos = fLibraryToOrdinal.find(lib);
-                       if ( pos != fLibraryToOrdinal.end() ) {
-                               if ( pos->second == EXECUTABLE_ORDINAL )
-                                       return BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE;
-                               else 
-                                       return pos->second;
-                       }
-                       break;
-               case ObjectFile::Atom::kWeakDefinition:
-                       throw "compressedOrdinalForImortedAtom() should not have been called on a weak definition";
-               case ObjectFile::Atom::kAbsoluteSymbol:
-               case ObjectFile::Atom::kRegularDefinition:
-               case ObjectFile::Atom::kTentativeDefinition:
-                       return BIND_SPECIAL_DYLIB_SELF;
-       }       
-
-       throw "can't find ordinal for imported symbol";
-}
-
-
-template <typename A>
-ObjectFile::Atom& Writer<A>::makeObjcInfoAtom(ObjectFile::Reader::ObjcConstraint objcContraint, bool objcReplacementClasses)
-{
-       
-       return *(new ObjCInfoAtom<A>(*this, objcContraint, objcReplacementClasses, fOptions.objCABIVersion2POverride()));
-}
-
-template <typename A>
-void Writer<A>::addSynthesizedAtoms(const std::vector<class ObjectFile::Atom*>& existingAtoms,
-                                                                 class ObjectFile::Atom* dyldClassicHelperAtom,
-                                                                 class ObjectFile::Atom* dyldCompressedHelperAtom,
-                                                                 class ObjectFile::Atom* dyldLazyDylibHelperAtom,
-                                                                 bool biggerThanTwoGigs,
-                                                                       uint32_t dylibSymbolCount,
-                                                                       std::vector<class ObjectFile::Atom*>& newAtoms)
-{
-       fDyldClassicHelperAtom = dyldClassicHelperAtom;
-       fDyldCompressedHelperAtom = dyldCompressedHelperAtom;
-       fDyldLazyDylibHelper = dyldLazyDylibHelperAtom;
-       fBiggerThanTwoGigs = biggerThanTwoGigs;
-       fDylibSymbolCountUpperBound = dylibSymbolCount;
-
-       // create inter-library stubs
-       synthesizeStubs(existingAtoms, newAtoms);
-}
-
-
-template <typename A>
-uint64_t Writer<A>::write(std::vector<class ObjectFile::Atom*>& atoms,
-                                                 std::vector<class ObjectFile::Reader::Stab>& stabs,
-                                                 class ObjectFile::Atom* entryPointAtom, 
-                                                 bool createUUID, bool canScatter, ObjectFile::Reader::CpuConstraint cpuConstraint,
-                                                 std::set<const class ObjectFile::Atom*>& atomsThatOverrideWeak,
-                                                 bool hasExternalWeakDefinitions)
-{
-       fAllAtoms =  &atoms;
-       fStabs =  &stabs;
-       fEntryPoint = entryPointAtom;
-       fCanScatter = canScatter;
-       fCpuConstraint = cpuConstraint;
-       fHasWeakExports = hasExternalWeakDefinitions; // dyld needs to search this image as if it had weak exports
-       fRegularDefAtomsThatOverrideADylibsWeakDef = &atomsThatOverrideWeak;
-       
-
-       try {
-               // Set for create UUID
-               if (createUUID)
-                       fUUIDAtom->generate();
-
-               // remove uneeded dylib load commands
-               optimizeDylibReferences();
-
-               // check for mdynamic-no-pic codegen
-               scanForAbsoluteReferences();
-
-               // create table of unwind info
-               synthesizeUnwindInfoTable();
-
-               // create SegmentInfo and SectionInfo objects and assign all atoms to a section
-               partitionIntoSections();
-
-               // segment load command can now be sized and padding can be set
-               adjustLoadCommandsAndPadding();
-
-               // assign each section a file offset
-               assignFileOffsets();
-
-               // if need to add branch islands, reassign file offsets
-               if ( addBranchIslands() )
-                       assignFileOffsets();
-       
-               // now that addresses are assigned, create unwind info 
-               if ( fUnwindInfoAtom != NULL ) {
-                       fUnwindInfoAtom->generate();
-                       // re-layout 
-                       adjustLoadCommandsAndPadding();
-                       assignFileOffsets();
-               }
-
-               // make spit-seg info now that all atoms exist
-               createSplitSegContent();
-
-               // build symbol table and relocations
-               buildLinkEdit();
-
-               // write map file if requested
-               writeMap();
-
-               // write everything
-               return writeAtoms();
-       } catch (...) {
-               // clean up if any errors
-               (void)unlink(fFilePath);
-               throw;
-       }
-}
-
-template <typename A>
-void Writer<A>::buildLinkEdit()
-{
-       this->collectExportedAndImportedAndLocalAtoms();
-       this->buildSymbolTable();
-       this->buildFixups();
-       this->adjustLinkEditSections();
-}
-
-
-
-template <typename A>
-uint64_t Writer<A>::getAtomLoadAddress(const ObjectFile::Atom* atom)
-{
-       return atom->getAddress();
-//     SectionInfo* info = (SectionInfo*)atom->getSection();
-//     return info->getBaseAddress() + atom->getSectionOffset();
-}
-
-template <>
-bool Writer<x86_64>::stringsNeedLabelsInObjects()
-{
-       return true;
-}
-
-template <typename A>
-bool Writer<A>::stringsNeedLabelsInObjects()
-{
-       return false;
-}
-
-template <typename A>
-const char* Writer<A>::symbolTableName(const ObjectFile::Atom* atom)
-{
-       static unsigned int counter = 0;
-       const char* name;
-       if ( stringsNeedLabelsInObjects() 
-               && (atom->getContentType() == ObjectFile::Atom::kCStringType) 
-               && (atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition) )
-               asprintf((char**)&name, "LC%u", counter++);
-       else
-               name = atom->getName();
-       return name;
-       return atom->getName();
-}
-
-template <typename A>
-void Writer<A>::setExportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
-{
-       // set n_strx
-       entry->set_n_strx(this->fStringsAtom->add(this->symbolTableName(atom)));
-
-       // set n_type
-       if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAsAbsolute ) {
-               entry->set_n_type(N_EXT | N_ABS);
-       }
-       else {
-               entry->set_n_type(N_EXT | N_SECT);
-               if ( (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit) && (fOptions.outputKind() == Options::kObjectFile) ) {
-                       if ( fOptions.keepPrivateExterns() )
-                               entry->set_n_type(N_EXT | N_SECT | N_PEXT);
-               }
-       }
-       
-       // set n_sect (section number of implementation )
-       uint8_t sectionIndex = atom->getSection()->getIndex();
-       entry->set_n_sect(sectionIndex);
-
-       // the __mh_execute_header is magic and must be an absolute symbol
-       if ( (sectionIndex==0) 
-               && (fOptions.outputKind() == Options::kDynamicExecutable)
-               && (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip ))
-               entry->set_n_type(N_EXT | N_ABS);
-
-       // set n_desc
-       uint16_t desc = 0;
-    if ( atom->isThumb() )
-        desc |= N_ARM_THUMB_DEF;
-    if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip )
-        desc |= REFERENCED_DYNAMICALLY;
-    if ( atom->dontDeadStrip() && (fOptions.outputKind() == Options::kObjectFile) )
-        desc |= N_NO_DEAD_STRIP;
-    if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition ) {
-        desc |= N_WEAK_DEF;
-        fHasWeakExports = true;
-    }
-       entry->set_n_desc(desc);
-
-       // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
-       if ( atom->getDefinitionKind() == ObjectFile::Atom::kAbsoluteSymbol ) 
-               entry->set_n_value(atom->getSectionOffset());
-       else
-               entry->set_n_value(this->getAtomLoadAddress(atom));
-}
-
-template <typename A>
-void Writer<A>::setImportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
-{
-       // set n_strx
-       entry->set_n_strx(this->fStringsAtom->add(atom->getName()));
-
-       // set n_type
-       if ( fOptions.outputKind() == Options::kObjectFile ) {
-               if ( (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit) 
-                               && (atom->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition) )
-                       entry->set_n_type(N_UNDF | N_EXT | N_PEXT);
-               else 
-                       entry->set_n_type(N_UNDF | N_EXT);
-       }
-       else {
-               if ( fOptions.prebind() )
-                       entry->set_n_type(N_PBUD | N_EXT);
-               else 
-                       entry->set_n_type(N_UNDF | N_EXT);
-       }
-
-       // set n_sect
-       entry->set_n_sect(0);
-
-       uint16_t desc = 0;
-       if ( fOptions.outputKind() != Options::kObjectFile ) {
-               // set n_desc ( high byte is library ordinal, low byte is reference type )
-               std::map<const ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fStubsMap.find(atom);
-               if ( pos != fStubsMap.end() || ( strncmp(atom->getName(), ".objc_class_name_", 17) == 0) )
-                       desc = REFERENCE_FLAG_UNDEFINED_LAZY;
-               else
-                       desc = REFERENCE_FLAG_UNDEFINED_NON_LAZY;
-               try {
-                       uint8_t ordinal = this->ordinalForLibrary(atom->getFile());
-                       //fprintf(stderr, "ordinal=%u from reader=%p for symbol=%s\n", ordinal, atom->getFile(), atom->getName());
-                       SET_LIBRARY_ORDINAL(desc, ordinal);
-               }
-               catch (const char* msg) {
-                       throwf("%s %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath());
-               }
-       }
-       else if ( atom->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition ) {
-               uint8_t align = atom->getAlignment().powerOf2;
-               // always record custom alignment of common symbols to match what compiler does
-               SET_COMM_ALIGN(desc, align);
-       }
-       if ( atom->isThumb() )
-               desc |= N_ARM_THUMB_DEF;
-       if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip )
-               desc |= REFERENCED_DYNAMICALLY;
-       if ( ( fOptions.outputKind() != Options::kObjectFile) && (atom->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
-               desc |= N_REF_TO_WEAK;
-               fReferencesWeakImports = true;
-       }
-       // set weak_import attribute
-       if ( fWeakImportMap[atom] ) 
-               desc |= N_WEAK_REF;
-       entry->set_n_desc(desc);
-
-       // set n_value, zero for import proxy and size for tentative definition
-       entry->set_n_value(atom->getSize());
-}
-
-
-template <typename A>
-void Writer<A>::setLocalNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
-{
-       // set n_strx
-       const char* symbolName = this->symbolTableName(atom);
-       char anonName[32];
-       if ( (fOptions.outputKind() == Options::kObjectFile) && !fOptions.keepLocalSymbol(symbolName) ) {
-               if ( stringsNeedLabelsInObjects() && (atom->getContentType() == ObjectFile::Atom::kCStringType) ) {
-                       // don't use 'l' labels for x86_64 strings
-                       // <rdar://problem/6605499> x86_64 obj-c runtime confused when static lib is stripped
-               }
-               else {
-                       sprintf(anonName, "l%u", fAnonNameIndex++);
-                       symbolName = anonName;
-               }
-       }
-       entry->set_n_strx(this->fStringsAtom->add(symbolName));
-
-       // set n_type
-       uint8_t type = N_SECT;
-       if ( atom->getDefinitionKind() == ObjectFile::Atom::kAbsoluteSymbol ) 
-               type = N_ABS;
-       if ( atom->getScope() == ObjectFile::Atom::scopeLinkageUnit )
-               type |= N_PEXT;
-       entry->set_n_type(type);
-
-       // set n_sect (section number of implementation )
-       uint8_t sectIndex = atom->getSection()->getIndex();
-       if ( sectIndex == 0 ) {
-               // see <mach-o/ldsyms.h> synthesized lable for mach_header needs special section number...
-               if ( strcmp(atom->getSectionName(), "._mach_header") == 0 )
-                       sectIndex = 1;
-       }
-       entry->set_n_sect(sectIndex);
-
-       // set n_desc
-       uint16_t desc = 0;
-    if ( atom->dontDeadStrip() && (fOptions.outputKind() == Options::kObjectFile) )
-        desc |= N_NO_DEAD_STRIP;
-       if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition )
-               desc |= N_WEAK_DEF;
-       if ( atom->isThumb() )
-               desc |= N_ARM_THUMB_DEF;
-       entry->set_n_desc(desc);
-
-       // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
-       if ( atom->getDefinitionKind() == ObjectFile::Atom::kAbsoluteSymbol ) 
-               entry->set_n_value(atom->getSectionOffset());
-       else
-               entry->set_n_value(this->getAtomLoadAddress(atom));
-}
-
-
-template <typename A>
-void Writer<A>::addLocalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name)
-{
-       macho_nlist<P> entry;
-       
-       // set n_strx
-       entry.set_n_strx(fStringsAtom->add(name));
-
-       // set n_type
-       entry.set_n_type(N_SECT);
-
-       // set n_sect (section number of implementation )
-       entry.set_n_sect(atom.getSection()->getIndex());
-
-       // set n_desc
-       entry.set_n_desc(0);
-
-       // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
-       entry.set_n_value(this->getAtomLoadAddress(&atom) + offsetInAtom);
-       
-       // add
-       fLocalExtraLabels.push_back(entry);
-}
-
-
-
-template <typename A>
-void Writer<A>::addGlobalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name)
-{
-       macho_nlist<P> entry;
-       
-       // set n_strx
-       entry.set_n_strx(fStringsAtom->add(name));
-
-       // set n_type
-       entry.set_n_type(N_SECT|N_EXT);
-
-       // set n_sect (section number of implementation )
-       entry.set_n_sect(atom.getSection()->getIndex());
-
-       // set n_desc
-       entry.set_n_desc(0);
-
-       // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
-       entry.set_n_value(this->getAtomLoadAddress(&atom) + offsetInAtom);
-       
-       // add
-       fGlobalExtraLabels.push_back(entry);
-}
-
-template <typename A>
-void Writer<A>::setNlistRange(std::vector<class ObjectFile::Atom*>& atoms, uint32_t startIndex, uint32_t count)
-{
-       macho_nlist<P>* entry = &fSymbolTable[startIndex];
-       for (uint32_t i=0; i < count; ++i, ++entry) {
-               ObjectFile::Atom* atom = atoms[i];
-               if ( &atoms == &fExportedAtoms ) {
-                       this->setExportNlist(atom, entry);
-               }
-               else if ( &atoms == &fImportedAtoms ) {
-                       this->setImportNlist(atom, entry);
-               }
-               else {
-                       this->setLocalNlist(atom, entry);
-               }
-       }
-}
-
-template <typename A>
-void Writer<A>::copyNlistRange(const std::vector<macho_nlist<P> >& entries, uint32_t startIndex)
-{
-       for ( typename std::vector<macho_nlist<P> >::const_iterator it = entries.begin(); it != entries.end(); ++it) 
-               fSymbolTable[startIndex++] = *it;
-}
-
-
-template <typename A>
-struct NListNameSorter
-{
-       NListNameSorter(StringsLinkEditAtom<A>* pool) : fStringPool(pool) {}
-       
-     bool operator()(const macho_nlist<typename A::P>& left, const macho_nlist<typename A::P>& right)
-     {
-          return (strcmp(fStringPool->stringForIndex(left.n_strx()), fStringPool->stringForIndex(right.n_strx())) < 0);
-     }
-private:
-       StringsLinkEditAtom<A>*         fStringPool;
-};
-
-
-template <typename A>
-void Writer<A>::buildSymbolTable()
-{
-       fSymbolTableStabsStartIndex             = 0;
-       fSymbolTableStabsCount                  = fStabs->size();
-       fSymbolTableLocalStartIndex             = fSymbolTableStabsStartIndex + fSymbolTableStabsCount;
-       fSymbolTableLocalCount                  = fLocalSymbolAtoms.size() + fLocalExtraLabels.size();
-       fSymbolTableExportStartIndex    = fSymbolTableLocalStartIndex + fSymbolTableLocalCount;
-       fSymbolTableExportCount                 = fExportedAtoms.size() + fGlobalExtraLabels.size();
-       fSymbolTableImportStartIndex    = fSymbolTableExportStartIndex + fSymbolTableExportCount;
-       fSymbolTableImportCount                 = fImportedAtoms.size();
-
-       // allocate symbol table
-       fSymbolTableCount = fSymbolTableStabsCount + fSymbolTableLocalCount + fSymbolTableExportCount + fSymbolTableImportCount;
-       fSymbolTable = new macho_nlist<P>[fSymbolTableCount];
-
-       // fill in symbol table and string pool (do stabs last so strings are at end of pool)
-       setNlistRange(fLocalSymbolAtoms, fSymbolTableLocalStartIndex,  fLocalSymbolAtoms.size());
-       if ( fLocalExtraLabels.size() != 0 )
-               copyNlistRange(fLocalExtraLabels, fSymbolTableLocalStartIndex+fLocalSymbolAtoms.size());
-       setNlistRange(fExportedAtoms,    fSymbolTableExportStartIndex, fExportedAtoms.size());
-       if ( fGlobalExtraLabels.size() != 0 ) {
-               copyNlistRange(fGlobalExtraLabels, fSymbolTableExportStartIndex+fExportedAtoms.size());
-               // re-sort combined range
-               std::sort(  &fSymbolTable[fSymbolTableExportStartIndex], 
-                                       &fSymbolTable[fSymbolTableExportStartIndex+fSymbolTableExportCount], 
-                                       NListNameSorter<A>(fStringsAtom) );
-       }
-       setNlistRange(fImportedAtoms,    fSymbolTableImportStartIndex, fSymbolTableImportCount);
-       addStabs(fSymbolTableStabsStartIndex);
-       
-       // set up module table
-       if ( fModuleInfoAtom != NULL )
-               fModuleInfoAtom->setName();
-               
-       // create atom to symbol index map
-       // imports
-       int i = 0;
-       for(std::vector<ObjectFile::Atom*>::iterator it=fImportedAtoms.begin(); it != fImportedAtoms.end(); ++it) {
-               fAtomToSymbolIndex[*it] = i + fSymbolTableImportStartIndex;
-               ++i;
-       }
-       // locals
-       i = 0;
-       for(std::vector<ObjectFile::Atom*>::iterator it=fLocalSymbolAtoms.begin(); it != fLocalSymbolAtoms.end(); ++it) {
-               fAtomToSymbolIndex[*it] = i + fSymbolTableLocalStartIndex;
-               ++i;
-       }
-       // exports
-       i = 0;
-       for(std::vector<ObjectFile::Atom*>::iterator it=fExportedAtoms.begin(); it != fExportedAtoms.end(); ++it) {
-               fAtomToSymbolIndex[*it] = i + fSymbolTableExportStartIndex;
-               ++i;
-       }
-       
-}
-
-
-
-template <typename A>
-bool Writer<A>::shouldExport(const ObjectFile::Atom& atom) const
-{
-       switch ( atom.getSymbolTableInclusion() ) {
-               case ObjectFile::Atom::kSymbolTableNotIn:
-                       return false;
-               case ObjectFile::Atom::kSymbolTableInAndNeverStrip:
-                       return true;
-               case ObjectFile::Atom::kSymbolTableInAsAbsolute:
-               case ObjectFile::Atom::kSymbolTableIn:
-                       switch ( atom.getScope() ) {
-                               case ObjectFile::Atom::scopeGlobal:
-                                       return true;
-                               case ObjectFile::Atom::scopeLinkageUnit:
-                                       return ( (fOptions.outputKind() == Options::kObjectFile) && fOptions.keepPrivateExterns() );
-                               default:
-                                       return false;
-                       }
-                       break;
-       }
-       return false;
-}
-
-template <typename A>
-void Writer<A>::collectExportedAndImportedAndLocalAtoms()
-{
-       const int atomCount = fAllAtoms->size();
-       // guess at sizes of each bucket to minimize re-allocations
-       fImportedAtoms.reserve(100);
-       fExportedAtoms.reserve(atomCount/2);
-       fLocalSymbolAtoms.reserve(atomCount);
-       
-       for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
-               std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
-               for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
-                       std::vector<ObjectFile::Atom*>& sectionAtoms = (*secit)->fAtoms;
-                       for (std::vector<ObjectFile::Atom*>::iterator ait = sectionAtoms.begin(); ait != sectionAtoms.end(); ++ait) {
-                               ObjectFile::Atom* atom = *ait;
-                               // only named atoms go in symbol table
-                               if ( atom->getName() != NULL ) {
-                                       // put atom into correct bucket: imports, exports, locals
-                                       //fprintf(stderr, "collectExportedAndImportedAndLocalAtoms() name=%s\n", atom->getDisplayName());
-                                       switch ( atom->getDefinitionKind() ) {
-                                               case ObjectFile::Atom::kExternalDefinition:
-                                               case ObjectFile::Atom::kExternalWeakDefinition:
-                                                       fImportedAtoms.push_back(atom);
-                                                       break;
-                                               case ObjectFile::Atom::kTentativeDefinition:
-                                                       if ( (fOptions.outputKind() == Options::kObjectFile) && !fOptions.readerOptions().fMakeTentativeDefinitionsReal ) {
-                                                               fImportedAtoms.push_back(atom);
-                                                               break;
-                                                       }
-                                                       // else fall into
-                                               case ObjectFile::Atom::kWeakDefinition:
-                                                       if ( stringsNeedLabelsInObjects() 
-                                                                       && (fOptions.outputKind() == Options::kObjectFile)      
-                                                                       && (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableIn) 
-                                                                       && (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit) 
-                                                                       && (atom->getContentType() == ObjectFile::Atom::kCStringType) ) {
-                                                               fLocalSymbolAtoms.push_back(atom);
-                                                               break;
-                                                       }
-                                                       // else fall into
-                                               case ObjectFile::Atom::kRegularDefinition:
-                                               case ObjectFile::Atom::kAbsoluteSymbol:
-                                                       if ( this->shouldExport(*atom) )
-                                                               fExportedAtoms.push_back(atom);
-                                                       else if ( (atom->getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn)
-                                                               && ((fOptions.outputKind() == Options::kObjectFile) || fOptions.keepLocalSymbol(atom->getName())) )
-                                                               fLocalSymbolAtoms.push_back(atom);
-                                                       break;
-                                       }
-                               }
-                               // when geneating a .o file, dtrace static probes become local labels
-                               if ( (fOptions.outputKind() == Options::kObjectFile) && !fOptions.readerOptions().fForStatic ) {
-                                       std::vector<ObjectFile::Reference*>&  references = atom->getReferences();
-                                       for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
-                                               ObjectFile::Reference* ref = *rit;
-                                               if ( ref->getKind() == A::kDtraceProbe ) {
-                                                       // dtrace probe points to be add back into generated .o file
-                                                       this->addLocalLabel(*atom, ref->getFixUpOffset(), ref->getTargetName());
-                                               }
-                                       }
-                               }
-                               // when linking kernel, old style dtrace static probes become global labels
-                               else if ( fOptions.readerOptions().fForStatic ) {
-                                       std::vector<ObjectFile::Reference*>&  references = atom->getReferences();
-                                       for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
-                                               ObjectFile::Reference* ref = *rit;
-                                               if ( ref->getKind() == A::kDtraceProbe ) {
-                                                       // dtrace probe points to be add back into generated .o file
-                                                       this->addGlobalLabel(*atom, ref->getFixUpOffset(), ref->getTargetName());
-                                               }
-                                       }
-                               }
-                       }
-               }
-       }
-
-       // sort exported atoms by name
-       std::sort(fExportedAtoms.begin(), fExportedAtoms.end(), AtomByNameSorter());
-       // sort imported atoms by name (not required by runtime, but helps make generated files binary diffable)
-       std::sort(fImportedAtoms.begin(), fImportedAtoms.end(), AtomByNameSorter());
-}
-
-
-template <typename A>
-uint64_t Writer<A>::valueForStab(const ObjectFile::Reader::Stab& stab)
-{
-       switch ( stab.type ) {
-               case N_FUN:
-                       if ( (stab.string == NULL) || (strlen(stab.string) == 0) ) {
-                               // end of function N_FUN has size
-                               return stab.atom->getSize();
-                       }
-                       else {
-                               // start of function N_FUN has address
-                               return getAtomLoadAddress(stab.atom);
-                       }
-               case N_LBRAC:
-               case N_RBRAC:
-               case N_SLINE:
-                       if ( stab.atom == NULL )
-                               // some weird assembly files have slines not associated with a function
-                               return stab.value;
-                       else
-                               // all these stab types need their value changed from an offset in the atom to an address
-                               return getAtomLoadAddress(stab.atom) + stab.value;
-               case N_STSYM:
-               case N_LCSYM:
-               case N_BNSYM:
-                       // all these need address of atom
-                       return getAtomLoadAddress(stab.atom);;
-               case N_ENSYM:
-                       return stab.atom->getSize();
-               case N_SO:
-                       if ( stab.atom == NULL ) {
-                               return 0;
-                       }
-                       else {
-                               if ( (stab.string == NULL) || (strlen(stab.string) == 0) ) {
-                                       // end of translation unit N_SO has address of end of last atom
-                                       return getAtomLoadAddress(stab.atom) + stab.atom->getSize();
-                               }
-                               else {
-                                       // start of translation unit N_SO has address of end of first atom
-                                       return getAtomLoadAddress(stab.atom);
-                               }
-                       }
-                       break;
-               default:
-                       return stab.value;
-       }
-}
-
-template <typename A>
-uint32_t Writer<A>::stringOffsetForStab(const ObjectFile::Reader::Stab& stab)
-{
-       switch (stab.type) {
-               case N_SO:
-                       if ( (stab.string == NULL) || stab.string[0] == '\0' ) {
-                               return this->fStringsAtom->emptyString();
-                               break;
-                       }
-                       // fall into uniquing case
-               case N_SOL:
-               case N_BINCL:
-               case N_EXCL:
-                       return this->fStringsAtom->addUnique(stab.string);
-                       break;
-               default:
-                       if ( stab.string == NULL )
-                               return 0;
-                       else if ( stab.string[0] == '\0' )
-                               return this->fStringsAtom->emptyString();
-                       else
-                               return this->fStringsAtom->add(stab.string);
-       }
-       return 0;
-}
-
-template <typename A>
-uint8_t Writer<A>::sectionIndexForStab(const ObjectFile::Reader::Stab& stab)
-{
-       // in FUN stabs, n_sect field is 0 for start FUN and 1 for end FUN
-       if ( stab.type == N_FUN )
-               return stab.other;
-       else if ( stab.atom != NULL ) 
-               return stab.atom->getSection()->getIndex();
-       else
-               return stab.other;
-}
-
-template <typename A>
-void Writer<A>::addStabs(uint32_t startIndex)
-{
-       macho_nlist<P>* entry = &fSymbolTable[startIndex];
-       for(std::vector<ObjectFile::Reader::Stab>::iterator it = fStabs->begin(); it != fStabs->end(); ++it, ++entry) {
-               const ObjectFile::Reader::Stab& stab = *it;
-               entry->set_n_type(stab.type);
-               entry->set_n_sect(sectionIndexForStab(stab));
-               entry->set_n_desc(stab.desc);
-               entry->set_n_value(valueForStab(stab));
-               entry->set_n_strx(stringOffsetForStab(stab));
-       }
-}
-
-
-
-template <typename A>
-uint32_t Writer<A>::symbolIndex(ObjectFile::Atom& atom)
-{
-       std::map<ObjectFile::Atom*, uint32_t>::iterator pos = fAtomToSymbolIndex.find(&atom);
-       if ( pos != fAtomToSymbolIndex.end() )
-               return pos->second;
-       throwf("atom not found in symbolIndex(%s) for %s", atom.getDisplayName(), atom.getFile()->getPath());
-}
-
-
-template <>
-bool Writer<x86_64>::makesExternalRelocatableReference(ObjectFile::Atom& target) const
-{
-       switch ( target.getSymbolTableInclusion() )      {
-               case ObjectFile::Atom::kSymbolTableNotIn:
-                       return false;
-               case ObjectFile::Atom::kSymbolTableInAsAbsolute:
-               case ObjectFile::Atom::kSymbolTableIn:
-               case ObjectFile::Atom::kSymbolTableInAndNeverStrip:
-                       return true;
-       };
-       return false;
-}
-
-template <typename A>
-bool Writer<A>::makesExternalRelocatableReference(ObjectFile::Atom& target) const
-{
-       switch ( target.getDefinitionKind() ) {
-               case ObjectFile::Atom::kRegularDefinition:
-               case ObjectFile::Atom::kWeakDefinition:
-               case ObjectFile::Atom::kAbsoluteSymbol:
-                       return false;
-               case ObjectFile::Atom::kTentativeDefinition:
-                       if ( fOptions.readerOptions().fMakeTentativeDefinitionsReal )
-                               return false;
-                       else
-                               return (target.getScope() != ObjectFile::Atom::scopeTranslationUnit);
-               case ObjectFile::Atom::kExternalDefinition:
-               case ObjectFile::Atom::kExternalWeakDefinition:
-                       return shouldExport(target);
-       }
-       return false;
-}
-
-template <typename A>
-void Writer<A>::buildFixups()
-{
-       if ( fOptions.outputKind() == Options::kObjectFile ) {
-               this->buildObjectFileFixups();
-       }
-       else {
-               if ( fOptions.keepRelocations() )
-                       this->buildObjectFileFixups();
-               this->buildExecutableFixups();
-       }
-}
-
-template <>
-uint32_t Writer<x86_64>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
-{
-       ObjectFile::Atom& target = ref->getTarget();
-       bool external = this->makesExternalRelocatableReference(target);
-       uint32_t symbolIndex = external ? this->symbolIndex(target) : target.getSection()->getIndex();
-       uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
-       macho_relocation_info<P> reloc1;
-       macho_relocation_info<P> reloc2;
-       x86_64::ReferenceKinds kind = (x86_64::ReferenceKinds)ref->getKind();
-
-       switch ( kind ) {
-               case x86_64::kNoFixUp:
-               case x86_64::kGOTNoFixUp:
-               case x86_64::kFollowOn:
-               case x86_64::kGroupSubordinate:
-                       return 0;
-
-               case x86_64::kPointer:
-               case x86_64::kPointerWeakImport:
-                       reloc1.set_r_address(address);
-                       reloc1.set_r_symbolnum(symbolIndex);
-                       reloc1.set_r_pcrel(false);
-                       reloc1.set_r_length(3);
-                       reloc1.set_r_extern(external);
-                       reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
-                       fSectionRelocs.push_back(reloc1);
-                       return 1;
-
-               case x86_64::kPointer32:
-                       reloc1.set_r_address(address);
-                       reloc1.set_r_symbolnum(symbolIndex);
-                       reloc1.set_r_pcrel(false);
-                       reloc1.set_r_length(2);
-                       reloc1.set_r_extern(external);
-                       reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
-                       fSectionRelocs.push_back(reloc1);
-                       return 1;
-
-               case x86_64::kPointerDiff32:
-               case x86_64::kPointerDiff:      
-                       {
-                       ObjectFile::Atom& fromTarget = ref->getFromTarget();
-                       bool fromExternal = (fromTarget.getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn);
-                       uint32_t fromSymbolIndex = fromExternal ? this->symbolIndex(fromTarget) : fromTarget.getSection()->getIndex();
-                       reloc1.set_r_address(address);
-                       reloc1.set_r_symbolnum(symbolIndex);
-                       reloc1.set_r_pcrel(false);
-                       reloc1.set_r_length(kind==x86_64::kPointerDiff32 ? 2 : 3);
-                       reloc1.set_r_extern(external);
-                       reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
-                       reloc2.set_r_address(address);
-                       reloc2.set_r_symbolnum(fromSymbolIndex);
-                       reloc2.set_r_pcrel(false);
-                       reloc2.set_r_length(kind==x86_64::kPointerDiff32 ? 2 : 3);
-                       reloc2.set_r_extern(fromExternal);
-                       reloc2.set_r_type(X86_64_RELOC_SUBTRACTOR);
-                       fSectionRelocs.push_back(reloc1);
-                       fSectionRelocs.push_back(reloc2);
-                       return 2;
-                       }
-
-               case x86_64::kBranchPCRel32:
-               case x86_64::kBranchPCRel32WeakImport:
-               case x86_64::kDtraceProbeSite:
-               case x86_64::kDtraceIsEnabledSite:
-                       reloc1.set_r_address(address);
-                       reloc1.set_r_symbolnum(symbolIndex);
-                       reloc1.set_r_pcrel(true);
-                       reloc1.set_r_length(2);
-                       reloc1.set_r_extern(external);
-                       reloc1.set_r_type(X86_64_RELOC_BRANCH);
-                       fSectionRelocs.push_back(reloc1);
-                       return 1;
-
-               case x86_64::kPCRel32:
-                       reloc1.set_r_address(address);
-                       reloc1.set_r_symbolnum(symbolIndex);
-                       reloc1.set_r_pcrel(true);
-                       reloc1.set_r_length(2);
-                       reloc1.set_r_extern(external);
-                       reloc1.set_r_type(X86_64_RELOC_SIGNED);
-                       fSectionRelocs.push_back(reloc1);
-                       return 1;
-
-               case x86_64::kPCRel32_1:
-                       reloc1.set_r_address(address);
-                       reloc1.set_r_symbolnum(symbolIndex);
-                       reloc1.set_r_pcrel(true);
-                       reloc1.set_r_length(2);
-                       reloc1.set_r_extern(external);
-                       reloc1.set_r_type(X86_64_RELOC_SIGNED_1);
-                       fSectionRelocs.push_back(reloc1);
-                       return 1;
-
-               case x86_64::kPCRel32_2:
-                       reloc1.set_r_address(address);
-                       reloc1.set_r_symbolnum(symbolIndex);
-                       reloc1.set_r_pcrel(true);
-                       reloc1.set_r_length(2);
-                       reloc1.set_r_extern(external);
-                       reloc1.set_r_type(X86_64_RELOC_SIGNED_2);
-                       fSectionRelocs.push_back(reloc1);
-                       return 1;
-
-               case x86_64::kPCRel32_4:
-                       reloc1.set_r_address(address);
-                       reloc1.set_r_symbolnum(symbolIndex);
-                       reloc1.set_r_pcrel(true);
-                       reloc1.set_r_length(2);
-                       reloc1.set_r_extern(external);
-                       reloc1.set_r_type(X86_64_RELOC_SIGNED_4);
-                       fSectionRelocs.push_back(reloc1);
-                       return 1;
-
-               case x86_64::kBranchPCRel8:
-                       reloc1.set_r_address(address);
-                       reloc1.set_r_symbolnum(symbolIndex);
-                       reloc1.set_r_pcrel(true);
-                       reloc1.set_r_length(0);
-                       reloc1.set_r_extern(external);
-                       reloc1.set_r_type(X86_64_RELOC_BRANCH);
-                       fSectionRelocs.push_back(reloc1);
-                       return 1;
-
-               case x86_64::kPCRel32GOT:
-               case x86_64::kPCRel32GOTWeakImport:
-                       reloc1.set_r_address(address);
-                       reloc1.set_r_symbolnum(symbolIndex);
-                       reloc1.set_r_pcrel(true);
-                       reloc1.set_r_length(2);
-                       reloc1.set_r_extern(external);
-                       reloc1.set_r_type(X86_64_RELOC_GOT);
-                       fSectionRelocs.push_back(reloc1);
-                       return 1;
-
-               case x86_64::kPCRel32GOTLoad:
-               case x86_64::kPCRel32GOTLoadWeakImport:
-                       reloc1.set_r_address(address);
-                       reloc1.set_r_symbolnum(symbolIndex);
-                       reloc1.set_r_pcrel(true);
-                       reloc1.set_r_length(2);
-                       reloc1.set_r_extern(external);
-                       reloc1.set_r_type(X86_64_RELOC_GOT_LOAD);
-                       fSectionRelocs.push_back(reloc1);
-                       return 1;
-                       
-               case x86_64::kPointerDiff24:
-                       throw "internal linker error, kPointerDiff24 can't be encoded into object files";
-
-               case x86_64::kImageOffset32:
-                       throw "internal linker error, kImageOffset32 can't be encoded into object files";
-
-               case x86_64::kSectionOffset24:
-                       throw "internal linker error, kSectionOffset24 can't be encoded into object files";
-
-               case x86_64::kDtraceTypeReference:
-               case x86_64::kDtraceProbe:
-                       // generates no relocs
-                       return 0;
-       }
-       return 0;
-}
-
-
-template <>
-uint32_t Writer<x86>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
-{
-       ObjectFile::Atom& target = ref->getTarget();
-       bool isExtern = this->makesExternalRelocatableReference(target);
-       uint32_t symbolIndex = 0;
-       if ( isExtern )
-               symbolIndex = this->symbolIndex(target);
-       uint32_t sectionNum = target.getSection()->getIndex();
-       uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
-       macho_relocation_info<P> reloc1;
-       macho_relocation_info<P> reloc2;
-       macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
-       macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
-       x86::ReferenceKinds kind = (x86::ReferenceKinds)ref->getKind();
-       
-       if ( !isExtern && (sectionNum == 0) && (target.getDefinitionKind() != ObjectFile::Atom::kAbsoluteSymbol) )
-               warning("section index == 0 for %s (kind=%d, scope=%d, inclusion=%d) in %s",
-                target.getDisplayName(), target.getDefinitionKind(), target.getScope(), target.getSymbolTableInclusion(), target.getFile()->getPath());
-
-
-       switch ( kind ) {
-               case x86::kNoFixUp:
-               case x86::kFollowOn:
-               case x86::kGroupSubordinate:
-                       return 0;
-
-               case x86::kPointer:
-               case x86::kPointerWeakImport:
-               case x86::kAbsolute32:
-                       if ( !isExtern && (ref->getTargetOffset() != 0) ) {
-                               // use scattered reloc is target offset is non-zero
-                               sreloc1->set_r_scattered(true);
-                               sreloc1->set_r_pcrel(false);
-                               sreloc1->set_r_length(2);
-                               sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
-                               sreloc1->set_r_address(address);
-                               sreloc1->set_r_value(target.getAddress());
-                       }
-                       else {
-                               reloc1.set_r_address(address);
-                               reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
-                               reloc1.set_r_pcrel(false);
-                               reloc1.set_r_length(2);
-                               reloc1.set_r_extern(isExtern);
-                               reloc1.set_r_type(GENERIC_RELOC_VANILLA);
-                       }
-                       fSectionRelocs.push_back(reloc1);
-                       return 1;
-
-               case x86::kPointerDiff16:
-               case x86::kPointerDiff:
-                       {
-                               //pint_t fromAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
-                               //fprintf(stderr, "addObjectRelocs(): refFromTarget=%s, refTarget=%s, refFromTargetAddr=0x%llX, refFromTargetOffset=0x%llX\n",
-                               //                      ref->getFromTarget().getDisplayName(), ref->getTarget().getDisplayName(), 
-                               //                      ref->getFromTarget().getAddress(), ref->getFromTargetOffset());
-                               sreloc1->set_r_scattered(true);
-                               sreloc1->set_r_pcrel(false);
-                               sreloc1->set_r_length( (kind==x86::kPointerDiff) ? 2 : 1 );
-                               if ( ref->getTarget().getScope() == ObjectFile::Atom::scopeTranslationUnit )
-                                       sreloc1->set_r_type(GENERIC_RELOC_LOCAL_SECTDIFF);
-                               else
-                                       sreloc1->set_r_type(GENERIC_RELOC_SECTDIFF);
-                               sreloc1->set_r_address(address);
-                               sreloc1->set_r_value(target.getAddress());
-                               
-                               sreloc2->set_r_scattered(true);
-                               sreloc2->set_r_pcrel(false);
-                               sreloc2->set_r_length( (kind==x86::kPointerDiff) ? 2 : 1 );
-                               sreloc2->set_r_type(GENERIC_RELOC_PAIR);
-                               sreloc2->set_r_address(0);
-                               if ( &ref->getFromTarget() == atom )
-                                       sreloc2->set_r_value(ref->getFromTarget().getAddress()+ref->getFromTargetOffset());
-                               else
-                                       sreloc2->set_r_value(ref->getFromTarget().getAddress());
-                               fSectionRelocs.push_back(reloc2);
-                               fSectionRelocs.push_back(reloc1);
-                               return 2;
-                       }
-
-               case x86::kPCRel32WeakImport:
-               case x86::kPCRel32:
-               case x86::kPCRel16:
-               case x86::kPCRel8:
-               case x86::kDtraceProbeSite:
-               case x86::kDtraceIsEnabledSite:
-                       if ( !isExtern && (ref->getTargetOffset() != 0) ) {
-                               // use scattered reloc is target offset is non-zero
-                               sreloc1->set_r_scattered(true);
-                               sreloc1->set_r_pcrel(true);
-                               sreloc1->set_r_length( (kind==x86::kPCRel8) ? 0 : ((kind==x86::kPCRel16) ? 1 : 2) );
-                               sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
-                               sreloc1->set_r_address(address);
-                               sreloc1->set_r_value(target.getAddress());
-                       }
-                       else {
-                               reloc1.set_r_address(address);
-                               reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
-                               reloc1.set_r_pcrel(true);
-                               reloc1.set_r_length( (kind==x86::kPCRel8) ? 0 : ((kind==x86::kPCRel16) ? 1 : 2) );
-                               reloc1.set_r_extern(isExtern);
-                               reloc1.set_r_type(GENERIC_RELOC_VANILLA);
-                       }
-                       fSectionRelocs.push_back(reloc1);
-                       return 1;
-                       
-               case x86::kPointerDiff24:
-                       throw "internal linker error, kPointerDiff24 can't be encoded into object files";
-
-               case x86::kImageOffset32:
-                       throw "internal linker error, kImageOffset32 can't be encoded into object files";
-                       
-               case x86::kSectionOffset24:
-                       throw "internal linker error, kSectionOffset24 can't be encoded into object files";
-
-               case x86::kDtraceTypeReference:
-               case x86::kDtraceProbe:
-                       // generates no relocs
-                       return 0;
-
-       }
-       return 0;
-}
-
-template <>
-uint32_t Writer<arm>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
-{
-       ObjectFile::Atom& target = ref->getTarget();
-       bool isExtern = this->makesExternalRelocatableReference(target);
-       uint32_t symbolIndex = 0;
-       if ( isExtern )
-               symbolIndex = this->symbolIndex(target);
-       uint32_t sectionNum = target.getSection()->getIndex();
-       uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
-       macho_relocation_info<P> reloc1;
-       macho_relocation_info<P> reloc2;
-       macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
-       macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
-       arm::ReferenceKinds kind = (arm::ReferenceKinds)ref->getKind();
-       
-       if ( !isExtern && (sectionNum == 0) && (target.getDefinitionKind() != ObjectFile::Atom::kAbsoluteSymbol) )
-               warning("section index == 0 for %s (kind=%d, scope=%d, inclusion=%d) in %s",
-                target.getDisplayName(), target.getDefinitionKind(), target.getScope(), target.getSymbolTableInclusion(), target.getFile()->getPath());
-
-
-       switch ( kind ) {
-               case arm::kNoFixUp:
-               case arm::kFollowOn:
-               case arm::kGroupSubordinate:
-                       return 0;
-
-               case arm::kPointer:
-               case arm::kReadOnlyPointer:
-               case arm::kPointerWeakImport:
-                       if ( !isExtern && (ref->getTargetOffset() != 0) ) {
-                               // use scattered reloc is target offset is non-zero
-                               sreloc1->set_r_scattered(true);
-                               sreloc1->set_r_pcrel(false);
-                               sreloc1->set_r_length(2);
-                               sreloc1->set_r_type(ARM_RELOC_VANILLA);
-                               sreloc1->set_r_address(address);
-                               sreloc1->set_r_value(target.getAddress());
-                       }
-                       else {
-                               reloc1.set_r_address(address);
-                               reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
-                               reloc1.set_r_pcrel(false);
-                               reloc1.set_r_length(2);
-                               reloc1.set_r_extern(isExtern);
-                               reloc1.set_r_type(ARM_RELOC_VANILLA);
-                       }
-                       fSectionRelocs.push_back(reloc1);
-                       return 1;
-
-               case arm::kPointerDiff:
-                       {
-                               sreloc1->set_r_scattered(true);
-                               sreloc1->set_r_pcrel(false);
-                               sreloc1->set_r_length(2);
-                               if ( ref->getTarget().getScope() == ObjectFile::Atom::scopeTranslationUnit )
-                                       sreloc1->set_r_type(ARM_RELOC_LOCAL_SECTDIFF);
-                               else
-                                       sreloc1->set_r_type(ARM_RELOC_SECTDIFF);
-                               sreloc1->set_r_address(address);
-                               if ( ref->getTargetOffset() >= target.getSize() )
-                                       sreloc1->set_r_value(target.getAddress());
-                               else
-                                       sreloc1->set_r_value(target.getAddress()+ref->getTargetOffset());
-                               sreloc2->set_r_scattered(true);
-                               sreloc2->set_r_pcrel(false);
-                               sreloc2->set_r_length(2);
-                               sreloc2->set_r_type(ARM_RELOC_PAIR);
-                               sreloc2->set_r_address(0);
-                               if ( &ref->getFromTarget() == atom ) {
-                                       unsigned int pcBaseOffset = atom->isThumb() ? 4 : 8;
-                                       if ( (ref->getFromTargetOffset() > pcBaseOffset) && (strncmp(atom->getSectionName(), "__text", 6) == 0) ) {
-                                               sreloc2->set_r_value(ref->getFromTarget().getAddress()+ref->getFromTargetOffset()-pcBaseOffset);
-                                       }
-                                       else
-                                               sreloc2->set_r_value(ref->getFromTarget().getAddress()+ref->getFromTargetOffset());
-                               }
-                               else
-                                       sreloc2->set_r_value(ref->getFromTarget().getAddress());
-                               fSectionRelocs.push_back(reloc2);
-                               fSectionRelocs.push_back(reloc1);
-                               return 2;
-                       }
-
-               case arm::kBranch24WeakImport:
-               case arm::kBranch24:
-               case arm::kDtraceProbeSite:
-               case arm::kDtraceIsEnabledSite:
-                       if ( !isExtern && (ref->getTargetOffset() != 0) ) {
-                               // use scattered reloc is target offset is non-zero
-                               sreloc1->set_r_scattered(true);
-                               sreloc1->set_r_pcrel(true);
-                               sreloc1->set_r_length(2);
-                               sreloc1->set_r_type(ARM_RELOC_BR24);
-                               sreloc1->set_r_address(address);
-                               sreloc1->set_r_value(target.getAddress());
-                       }
-                       else {
-                               reloc1.set_r_address(address);
-                               reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
-                               reloc1.set_r_pcrel(true);
-                               reloc1.set_r_length(2);
-                               reloc1.set_r_extern(isExtern);
-                               reloc1.set_r_type(ARM_RELOC_BR24);
-                       }
-                       fSectionRelocs.push_back(reloc1);
-                       return 1;
-                       
-               case arm::kThumbBranch22WeakImport:
-               case arm::kThumbBranch22:
-                       if ( !isExtern && (ref->getTargetOffset() != 0) ) {
-                               // use scattered reloc if target offset is non-zero
-                               sreloc1->set_r_scattered(true);
-                               sreloc1->set_r_pcrel(true);
-                               sreloc1->set_r_length(2);
-                               sreloc1->set_r_type(ARM_THUMB_RELOC_BR22);
-                               sreloc1->set_r_address(address);
-                               sreloc1->set_r_value(target.getAddress());
-                       }
-                       else {
-                               reloc1.set_r_address(address);
-                               reloc1.set_r_symbolnum(isExtern ? symbolIndex : sectionNum);
-                               reloc1.set_r_pcrel(true);
-                               reloc1.set_r_length(2);
-                               reloc1.set_r_extern(isExtern);
-                               reloc1.set_r_type(ARM_THUMB_RELOC_BR22);
-                       }
-                       fSectionRelocs.push_back(reloc1);
-                       return 1;
-
-               case arm::kPointerDiff12:
-                       throw "internal error.  no reloc for 12-bit pointer diffs";
-
-               case arm::kDtraceTypeReference:
-               case arm::kDtraceProbe:
-                       // generates no relocs
-                       return 0;
-
-       }
-       return 0;
-}
-
-template <> uint64_t    Writer<ppc>::maxAddress() { return 0xFFFFFFFFULL; }
-template <> uint64_t  Writer<ppc64>::maxAddress() { return 0xFFFFFFFFFFFFFFFFULL; }
-template <> uint64_t    Writer<x86>::maxAddress() { return 0xFFFFFFFFULL; }
-template <> uint64_t Writer<x86_64>::maxAddress() { return 0xFFFFFFFFFFFFFFFFULL; }
-template <> uint64_t    Writer<arm>::maxAddress() { return 0xFFFFFFFFULL; }
-
-template <>
-uint8_t Writer<ppc>::getRelocPointerSize()
-{
-       return 2;
-}
-
-template <>
-uint8_t Writer<ppc64>::getRelocPointerSize()
-{
-       return 3;
-}
-
-template <>
-uint32_t Writer<ppc>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
-{
-       return addObjectRelocs_powerpc(atom, ref);
-}
-
-template <>
-uint32_t Writer<ppc64>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
-{
-       return addObjectRelocs_powerpc(atom, ref);
-}
-
-//
-// addObjectRelocs<ppc> and addObjectRelocs<ppc64> are almost exactly the same, so
-// they use a common addObjectRelocs_powerpc() method.
-//
-template <typename A>
-uint32_t Writer<A>::addObjectRelocs_powerpc(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
-{
-       ObjectFile::Atom& target = ref->getTarget();
-       bool isExtern = this->makesExternalRelocatableReference(target);        
-       uint32_t symbolIndex = 0;
-       if ( isExtern )
-               symbolIndex = this->symbolIndex(target);
-       uint32_t sectionNum = target.getSection()->getIndex();
-       uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
-       macho_relocation_info<P> reloc1;
-       macho_relocation_info<P> reloc2;
-       macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
-       macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
-       typename A::ReferenceKinds kind = (typename A::ReferenceKinds)ref->getKind();
-
-       switch ( kind ) {
-               case A::kNoFixUp:
-               case A::kFollowOn:
-               case A::kGroupSubordinate:
-                       return 0;
-
-               case A::kPointer:
-               case A::kPointerWeakImport:
-                       if ( !isExtern && (ref->getTargetOffset() >= target.getSize()) ) {
-                               // use scattered reloc is target offset is outside target
-                               sreloc1->set_r_scattered(true);
-                               sreloc1->set_r_pcrel(false);
-                               sreloc1->set_r_length(getRelocPointerSize());
-                               sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
-                               sreloc1->set_r_address(address);
-                               sreloc1->set_r_value(target.getAddress());
-                       }
-                       else {
-                               reloc1.set_r_address(address);
-                               if ( isExtern )
-                                       reloc1.set_r_symbolnum(symbolIndex);
-                               else
-                                       reloc1.set_r_symbolnum(sectionNum);
-                               reloc1.set_r_pcrel(false);
-                               reloc1.set_r_length(getRelocPointerSize());
-                               reloc1.set_r_extern(isExtern);
-                               reloc1.set_r_type(GENERIC_RELOC_VANILLA);
-                       }
-                       fSectionRelocs.push_back(reloc1);
-                       return 1;
-
-               case A::kPointerDiff16:
-               case A::kPointerDiff32:
-               case A::kPointerDiff64:
-                       {
-                               sreloc1->set_r_scattered(true);
-                               sreloc1->set_r_pcrel(false);
-                               sreloc1->set_r_length( (kind == A::kPointerDiff32) ? 2 : ((kind == A::kPointerDiff64) ? 3 : 1));
-                               if ( ref->getTarget().getScope() == ObjectFile::Atom::scopeTranslationUnit )
-                                       sreloc1->set_r_type(PPC_RELOC_LOCAL_SECTDIFF);
-                               else
-                                       sreloc1->set_r_type(PPC_RELOC_SECTDIFF);
-                               sreloc1->set_r_address(address);
-                               sreloc1->set_r_value(target.getAddress()); 
-                               sreloc2->set_r_scattered(true);
-                               sreloc2->set_r_pcrel(false);
-                               sreloc2->set_r_length(sreloc1->r_length());
-                               sreloc2->set_r_type(PPC_RELOC_PAIR);
-                               sreloc2->set_r_address(0);
-                               sreloc2->set_r_value(ref->getFromTarget().getAddress()+ref->getFromTargetOffset()); 
-                               fSectionRelocs.push_back(reloc2);
-                               fSectionRelocs.push_back(reloc1);
-                               return 2;
-                       }
-
-               case A::kBranch24WeakImport:
-               case A::kBranch24:
-               case A::kDtraceProbeSite:
-               case A::kDtraceIsEnabledSite:
-                       if ( (ref->getTargetOffset() == 0) || isExtern ) {
-                               reloc1.set_r_address(address);
-                               if ( isExtern )
-                                       reloc1.set_r_symbolnum(symbolIndex);
-                               else
-                                       reloc1.set_r_symbolnum(sectionNum);
-                               reloc1.set_r_pcrel(true);
-                               reloc1.set_r_length(2);
-                               reloc1.set_r_type(PPC_RELOC_BR24);
-                               reloc1.set_r_extern(isExtern);
-                       }
-                       else {
-                               sreloc1->set_r_scattered(true);
-                               sreloc1->set_r_pcrel(true);
-                               sreloc1->set_r_length(2);
-                               sreloc1->set_r_type(PPC_RELOC_BR24);
-                               sreloc1->set_r_address(address);
-                               sreloc1->set_r_value(target.getAddress());
-                       }
-                       fSectionRelocs.push_back(reloc1);
-                       return 1;
-
-               case A::kBranch14:
-                       if ( (ref->getTargetOffset() == 0) || isExtern ) {
-                               reloc1.set_r_address(address);
-                               if ( isExtern )
-                                       reloc1.set_r_symbolnum(symbolIndex);
-                               else
-                                       reloc1.set_r_symbolnum(sectionNum);
-                               reloc1.set_r_pcrel(true);
-                               reloc1.set_r_length(2);
-                               reloc1.set_r_type(PPC_RELOC_BR14);
-                               reloc1.set_r_extern(isExtern);
-                       }
-                       else {
-                               sreloc1->set_r_scattered(true);
-                               sreloc1->set_r_pcrel(true);
-                               sreloc1->set_r_length(2);
-                               sreloc1->set_r_type(PPC_RELOC_BR14);
-                               sreloc1->set_r_address(address);
-                               sreloc1->set_r_value(target.getAddress());
-                       }
-                       fSectionRelocs.push_back(reloc1);
-                       return 1;
-
-               case A::kPICBaseLow16:
-               case A::kPICBaseLow14:
-                       {
-                               pint_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
-                               pint_t toAddr = target.getAddress() + ref->getTargetOffset();
-                               sreloc1->set_r_scattered(true);
-                               sreloc1->set_r_pcrel(false);
-                               sreloc1->set_r_length(2);
-                               sreloc1->set_r_type(kind == A::kPICBaseLow16 ? PPC_RELOC_LO16_SECTDIFF : PPC_RELOC_LO14_SECTDIFF);
-                               sreloc1->set_r_address(address);
-                               sreloc1->set_r_value(target.getAddress());
-                               sreloc2->set_r_scattered(true);
-                               sreloc2->set_r_pcrel(false);
-                               sreloc2->set_r_length(2);
-                               sreloc2->set_r_type(PPC_RELOC_PAIR);
-                               sreloc2->set_r_address(((toAddr-fromAddr) >> 16) & 0xFFFF);
-                               sreloc2->set_r_value(fromAddr);
-                               fSectionRelocs.push_back(reloc2);
-                               fSectionRelocs.push_back(reloc1);
-                               return 2;
-                       }
-
-               case A::kPICBaseHigh16:
-                       {
-                               pint_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
-                               pint_t toAddr = target.getAddress() + ref->getTargetOffset();
-                               sreloc1->set_r_scattered(true);
-                               sreloc1->set_r_pcrel(false);
-                               sreloc1->set_r_length(2);
-                               sreloc1->set_r_type(PPC_RELOC_HA16_SECTDIFF);
-                               sreloc1->set_r_address(address);
-                               sreloc1->set_r_value(target.getAddress());
-                               sreloc2->set_r_scattered(true);
-                               sreloc2->set_r_pcrel(false);
-                               sreloc2->set_r_length(2);
-                               sreloc2->set_r_type(PPC_RELOC_PAIR);
-                               sreloc2->set_r_address((toAddr-fromAddr) & 0xFFFF);
-                               sreloc2->set_r_value(fromAddr);
-                               fSectionRelocs.push_back(reloc2);
-                               fSectionRelocs.push_back(reloc1);
-                               return 2;
-                       }
-
-               case A::kAbsLow14:
-               case A::kAbsLow16:
-                       {
-                               pint_t toAddr = target.getAddress() + ref->getTargetOffset();
-                               if ( (ref->getTargetOffset() == 0) || isExtern ) {
-                                       reloc1.set_r_address(address);
-                                       if ( isExtern )
-                                               reloc1.set_r_symbolnum(symbolIndex);
-                                       else
-                                               reloc1.set_r_symbolnum(sectionNum);
-                                       reloc1.set_r_pcrel(false);
-                                       reloc1.set_r_length(2);
-                                       reloc1.set_r_extern(isExtern);
-                                       reloc1.set_r_type(kind==A::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
-                               }
-                               else {
-                                       sreloc1->set_r_scattered(true);
-                                       sreloc1->set_r_pcrel(false);
-                                       sreloc1->set_r_length(2);
-                                       sreloc1->set_r_type(kind==A::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
-                                       sreloc1->set_r_address(address);
-                                       sreloc1->set_r_value(target.getAddress());
-                               }
-                               if ( isExtern )
-                                       reloc2.set_r_address(ref->getTargetOffset() >> 16);
-                               else
-                                       reloc2.set_r_address(toAddr >> 16);
-                               reloc2.set_r_symbolnum(0);
-                               reloc2.set_r_pcrel(false);
-                               reloc2.set_r_length(2);
-                               reloc2.set_r_extern(false);
-                               reloc2.set_r_type(PPC_RELOC_PAIR);
-                               fSectionRelocs.push_back(reloc2);
-                               fSectionRelocs.push_back(reloc1);
-                               return 2;
-                       }
-
-               case A::kAbsHigh16:
-                       {
-                               pint_t toAddr = target.getAddress() + ref->getTargetOffset();
-                               if ( (ref->getTargetOffset() == 0) || isExtern ) {
-                                       reloc1.set_r_address(address);
-                                       if ( isExtern )
-                                               reloc1.set_r_symbolnum(symbolIndex);
-                                       else
-                                               reloc1.set_r_symbolnum(sectionNum);
-                                       reloc1.set_r_pcrel(false);
-                                       reloc1.set_r_length(2);
-                                       reloc1.set_r_extern(isExtern);
-                                       reloc1.set_r_type(PPC_RELOC_HI16);
-                               }
-                               else {
-                                       sreloc1->set_r_scattered(true);
-                                       sreloc1->set_r_pcrel(false);
-                                       sreloc1->set_r_length(2);
-                                       sreloc1->set_r_type(PPC_RELOC_HI16);
-                                       sreloc1->set_r_address(address);
-                                       sreloc1->set_r_value(target.getAddress());
-                               }
-                               if ( isExtern )
-                                       reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF);
-                               else
-                                       reloc2.set_r_address(toAddr & 0xFFFF);
-                               reloc2.set_r_symbolnum(0);
-                               reloc2.set_r_pcrel(false);
-                               reloc2.set_r_length(2);
-                               reloc2.set_r_extern(false);
-                               reloc2.set_r_type(PPC_RELOC_PAIR);
-                               fSectionRelocs.push_back(reloc2);
-                               fSectionRelocs.push_back(reloc1);
-                               return 2;
-                       }
-
-               case A::kAbsHigh16AddLow:
-                       {
-                               pint_t toAddr = target.getAddress() + ref->getTargetOffset();
-                               uint32_t overflow = 0;
-                               if ( (toAddr & 0x00008000) != 0 )
-                                       overflow = 0x10000;
-                               if ( (ref->getTargetOffset() == 0) || isExtern ) {
-                                       reloc1.set_r_address(address);
-                                       if ( isExtern )
-                                               reloc1.set_r_symbolnum(symbolIndex);
-                                       else
-                                               reloc1.set_r_symbolnum(sectionNum);
-                                       reloc1.set_r_pcrel(false);
-                                       reloc1.set_r_length(2);
-                                       reloc1.set_r_extern(isExtern);
-                                       reloc1.set_r_type(PPC_RELOC_HA16);
-                               }
-                               else {
-                                       sreloc1->set_r_scattered(true);
-                                       sreloc1->set_r_pcrel(false);
-                                       sreloc1->set_r_length(2);
-                                       sreloc1->set_r_type(PPC_RELOC_HA16);
-                                       sreloc1->set_r_address(address);
-                                       sreloc1->set_r_value(target.getAddress());
-                               }
-                               if ( isExtern )
-                                       reloc2.set_r_address(ref->getTargetOffset() & 0xFFFF);
-                               else
-                                       reloc2.set_r_address(toAddr & 0xFFFF);
-                               reloc2.set_r_symbolnum(0);
-                               reloc2.set_r_pcrel(false);
-                               reloc2.set_r_length(2);
-                               reloc2.set_r_extern(false);
-                               reloc2.set_r_type(PPC_RELOC_PAIR);
-                               fSectionRelocs.push_back(reloc2);
-                               fSectionRelocs.push_back(reloc1);
-                               return 2;
-                       }
-
-               case A::kDtraceTypeReference:
-               case A::kDtraceProbe:
-                       // generates no relocs
-                       return 0;
-       }
-       return 0;
-}
-
-
-
-//
-// There are cases when an entry in the indirect symbol table is the magic value
-// INDIRECT_SYMBOL_LOCAL instead of being a symbol index.  When that happens
-// the content of the corresponding part of the __nl_symbol_pointer section
-// must also change. 
-//
-template <typename A>
-bool Writer<A>::indirectSymbolInRelocatableIsLocal(const ObjectFile::Reference* ref) const
-{
-       // cannot use INDIRECT_SYMBOL_LOCAL to tentative definitions in object files
-       // because tentative defs don't have addresses
-       if ( ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition )
-               return false;
-               
-       // must use INDIRECT_SYMBOL_LOCAL if there is an addend 
-       if ( ref->getTargetOffset() != 0 )
-               return true;
-       
-       // don't use INDIRECT_SYMBOL_LOCAL for external symbols
-       return ! this->shouldExport(ref->getTarget());
-}
-
-
-template <typename A>
-void Writer<A>::buildObjectFileFixups()
-{
-       uint32_t relocIndex = 0;
-       std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
-       const int segCount = segmentInfos.size();
-       for(int i=0; i < segCount; ++i) {
-               SegmentInfo* curSegment = segmentInfos[i];
-               std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
-               const int sectionCount = sectionInfos.size();
-               for(int j=0; j < sectionCount; ++j) {
-                       SectionInfo* curSection = sectionInfos[j];
-                       //fprintf(stderr, "buildObjectFileFixups(): starting section %s\n", curSection->fSectionName);
-                       std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
-                       if ( ! curSection->fAllZeroFill ) {
-                               if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers
-                                                       || curSection->fAllLazyDylibPointers || curSection->fAllStubs )
-                                       curSection->fIndirectSymbolOffset = fIndirectTableAtom->fTable.size();
-                               curSection->fRelocOffset = relocIndex;
-                               const int atomCount = sectionAtoms.size();
-                               for (int k=0; k < atomCount; ++k) {
-                                       ObjectFile::Atom* atom = sectionAtoms[k];
-                                       //fprintf(stderr, "buildObjectFileFixups(): atom %s has %lu references\n", atom->getDisplayName(), atom->getReferences().size());
-                                       std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
-                                       const int refCount = refs.size();
-                                       for (int l=0; l < refCount; ++l) {
-                                               ObjectFile::Reference* ref = refs[l];
-                                               if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers 
-                                                                               || curSection->fAllLazyDylibPointers || curSection->fAllStubs ) {
-                                                       uint32_t offsetInSection = atom->getSectionOffset();
-                                                       uint32_t indexInSection = offsetInSection / atom->getSize();
-                                                       uint32_t undefinedSymbolIndex;
-                                                       if ( curSection->fAllStubs ) {
-                                                               ObjectFile::Atom& stubTarget =ref->getTarget();
-                                                               ObjectFile::Atom& stubTargetTarget = stubTarget.getReferences()[0]->getTarget();
-                                                               undefinedSymbolIndex = this->symbolIndex(stubTargetTarget);
-                                                               //fprintf(stderr, "stub %s ==> %s ==> %s ==> index:%u\n", atom->getDisplayName(), stubTarget.getDisplayName(), stubTargetTarget.getDisplayName(), undefinedSymbolIndex);
-                                                       }
-                                                       else if ( curSection->fAllNonLazyPointers) {
-                                                               // only use INDIRECT_SYMBOL_LOCAL in non-lazy-pointers for atoms that won't be in symbol table or have an addend
-                                                               if ( this->indirectSymbolInRelocatableIsLocal(ref) )
-                                                                       undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
-                                                               else
-                                                                       undefinedSymbolIndex = this->symbolIndex(ref->getTarget());
-                                                       }
-                                                       else {
-                                                               // should never get here, fAllLazyPointers not used in generated .o files
-                                                               undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
-                                                       }
-                                                       uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
-                                                       IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
-                                                       //printf("fIndirectTableAtom->fTable.add(sectionIndex=%u, indirectTableIndex=%u => %u), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, atom->getSize());
-                                                       fIndirectTableAtom->fTable.push_back(entry);
-                                                       if ( curSection->fAllLazyPointers ) {
-                                                               ObjectFile::Atom& target = ref->getTarget();
-                                                               ObjectFile::Atom& fromTarget = ref->getFromTarget();
-                                                               if ( &fromTarget == NULL ) {
-                                                                       warning("lazy pointer %s missing initial binding", atom->getDisplayName());
-                                                               }
-                                                               else {
-                                                                       bool isExtern = ( ((target.getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
-                                                                               || (target.getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition))
-                                                                               && (target.getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn) );
-                                                                       macho_relocation_info<P> reloc1;
-                                                                       reloc1.set_r_address(atom->getSectionOffset());
-                                                                       reloc1.set_r_symbolnum(isExtern ? this->symbolIndex(target) : target.getSection()->getIndex());
-                                                                       reloc1.set_r_pcrel(false);
-                                                                       reloc1.set_r_length();
-                                                                       reloc1.set_r_extern(isExtern);
-                                                                       reloc1.set_r_type(GENERIC_RELOC_VANILLA);
-                                                                       fSectionRelocs.push_back(reloc1);
-                                                                       ++relocIndex;
-                                                               }
-                                                       }
-                                                       else if ( curSection->fAllStubs ) {
-                                                               relocIndex += this->addObjectRelocs(atom, ref);
-                                                       }
-                                               }
-                                               else if ( (ref->getKind() != A::kNoFixUp) && (ref->getTargetBinding() != ObjectFile::Reference::kDontBind) ) {
-                                                       relocIndex += this->addObjectRelocs(atom, ref);
-                                               }
-                                       }
-                               }
-                               curSection->fRelocCount = relocIndex - curSection->fRelocOffset;
-                       }
-               }
-       }
-
-       // reverse the relocs
-       std::reverse(fSectionRelocs.begin(), fSectionRelocs.end());
-       
-       // now reverse section reloc offsets
-       for(int i=0; i < segCount; ++i) {
-               SegmentInfo* curSegment = segmentInfos[i];
-               std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
-               const int sectionCount = sectionInfos.size();
-               for(int j=0; j < sectionCount; ++j) {
-                       SectionInfo* curSection = sectionInfos[j];
-                       curSection->fRelocOffset = relocIndex - curSection->fRelocOffset - curSection->fRelocCount;
-               }
-       }
-
-}
-
-
-template <>
-uint64_t Writer<x86_64>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom)  const
-{
-       uint64_t result;
-       if ( fOptions.outputKind() == Options::kKextBundle ) {
-               // for x86_64 kext bundles, the r_address field in relocs 
-               // is the offset from the start address of the first segment
-               result = address - fSegmentInfos[0]->fBaseAddress;
-               if ( result > 0xFFFFFFFF ) {
-                       throwf("kext bundle too large: address can't fit in 31-bit r_address field in %s from %s",
-                               atom->getDisplayName(), atom->getFile()->getPath());
-               }
-       }
-       else {
-               // for x86_64, the r_address field in relocs for final linked images 
-               // is the offset from the start address of the first writable segment
-               result = address - fFirstWritableSegment->fBaseAddress;
-               if ( result > 0xFFFFFFFF ) {
-                       if ( strcmp(atom->getSegment().getName(), "__TEXT") == 0 )
-                               throwf("text relocs not supported for x86_64 in %s from %s",
-                                               atom->getDisplayName(), atom->getFile()->getPath());
-                       else
-                               throwf("image too large: address can't fit in 32-bit r_address field in %s from %s",
-                                               atom->getDisplayName(), atom->getFile()->getPath());
-               }
-       }
-       return result;
-}
-
-
-template <>
-bool Writer<ppc>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
-{
-       switch ( ref.getKind() ) {
-               case ppc::kAbsLow16:
-               case ppc::kAbsLow14:
-               case ppc::kAbsHigh16:
-               case ppc::kAbsHigh16AddLow:
-                       if ( fSlideable )
-                               return true;
-       }
-       return false;
-}
-
-
-template <>
-bool Writer<ppc64>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
-{
-       switch ( ref.getKind() ) {
-               case ppc::kAbsLow16:
-               case ppc::kAbsLow14:
-               case ppc::kAbsHigh16:
-               case ppc::kAbsHigh16AddLow:
-                       if ( fSlideable )
-                               return true;
-       }
-       return false;
-}
-
-template <>
-bool Writer<x86>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
-{
-       if ( ref.getKind() == x86::kAbsolute32 ) {
-               switch ( ref.getTarget().getDefinitionKind() ) {
-                       case ObjectFile::Atom::kTentativeDefinition:
-                       case ObjectFile::Atom::kRegularDefinition:
-                       case ObjectFile::Atom::kWeakDefinition:
-                               // illegal in dylibs/bundles, until we support TEXT relocs 
-                               return fSlideable;
-                       case ObjectFile::Atom::kExternalDefinition:
-                       case ObjectFile::Atom::kExternalWeakDefinition:
-                               // illegal until we support TEXT relocs
-                               return true;
-                       case ObjectFile::Atom::kAbsoluteSymbol:
-                               // absolute symbbols only allowed in static executables
-                               return ( fOptions.outputKind() != Options::kStaticExecutable);
-               }
-       }
-       return false;
-}
-
-template <>
-bool Writer<x86_64>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
-{
-       if ( fOptions.outputKind() == Options::kKextBundle ) {
-               switch ( ref.getTarget().getDefinitionKind() ) {
-                       case ObjectFile::Atom::kTentativeDefinition:
-                       case ObjectFile::Atom::kRegularDefinition:
-                       case ObjectFile::Atom::kWeakDefinition:
-                       case ObjectFile::Atom::kAbsoluteSymbol:
-                               return false;
-                       case ObjectFile::Atom::kExternalDefinition:
-                       case ObjectFile::Atom::kExternalWeakDefinition:
-                               // true means we need a TEXT relocs
-                               switch ( ref.getKind() ) {
-                                       case x86_64::kBranchPCRel32:
-                                       case x86_64::kBranchPCRel32WeakImport:
-                                       case x86_64::kPCRel32GOTLoad:
-                                       case x86_64::kPCRel32GOTLoadWeakImport:
-                                       case x86_64::kPCRel32GOT:
-                                       case x86_64::kPCRel32GOTWeakImport:
-                                               return true;
-                               }
-                               break;
-               }
-       }
-       return false;
-}
-
-template <>
-bool Writer<arm>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref)
-{
-       switch ( fOptions.outputKind()) {
-               case Options::kStaticExecutable:
-               case Options::kPreload:
-                       // all relocations allowed in static executables
-                       return false;
-               default:
-                       break;
-       }
-       if ( ref.getKind() == arm::kReadOnlyPointer ) {
-               switch ( ref.getTarget().getDefinitionKind() ) {
-                       case ObjectFile::Atom::kTentativeDefinition:
-                       case ObjectFile::Atom::kRegularDefinition:
-                       case ObjectFile::Atom::kWeakDefinition:
-                               // illegal in dylibs/bundles, until we support TEXT relocs 
-                               return fSlideable;
-                       case ObjectFile::Atom::kExternalDefinition:
-                       case ObjectFile::Atom::kExternalWeakDefinition:
-                               // illegal until we support TEXT relocs
-                               return true;
-                       case ObjectFile::Atom::kAbsoluteSymbol:
-                               // absolute symbbols only allowed in static executables
-                               return true;
-               }
-       }
-       return false;
-}
-
-template <>
-bool Writer<x86>::generatesLocalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
-{
-       if ( ref.getKind() == x86::kAbsolute32 ) {
-               switch ( ref.getTarget().getDefinitionKind() ) {
-                       case ObjectFile::Atom::kTentativeDefinition:
-                       case ObjectFile::Atom::kRegularDefinition:
-                       case ObjectFile::Atom::kWeakDefinition:
-                               // a reference to the absolute address of something in this same linkage unit can be 
-                               // encoded as a local text reloc in a dylib or bundle 
-                               if ( fSlideable ) {
-                                       macho_relocation_info<P> reloc;
-                                       SectionInfo* sectInfo = (SectionInfo*)(ref.getTarget().getSection());
-                                       reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
-                                       reloc.set_r_symbolnum(sectInfo->getIndex());
-                                       reloc.set_r_pcrel(false);
-                                       reloc.set_r_length();
-                                       reloc.set_r_extern(false);
-                                       reloc.set_r_type(GENERIC_RELOC_VANILLA);
-                                       fInternalRelocs.push_back(reloc);
-                                       atomSection->fHasTextLocalRelocs = true;
-                                       if ( fOptions.makeCompressedDyldInfo() ) {
-                                               fRebaseInfo.push_back(RebaseInfo(REBASE_TYPE_TEXT_ABSOLUTE32, atom.getAddress() + ref.getFixUpOffset()));
-                                       }
-                                       return true;
-                               }
-                               return false;
-                       case ObjectFile::Atom::kExternalDefinition:
-                       case ObjectFile::Atom::kExternalWeakDefinition:
-                       case ObjectFile::Atom::kAbsoluteSymbol:
-                               return false;
-               }
-       }
-       return false;
-}
-
-template <>
-bool Writer<ppc>::generatesLocalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
-{
-       macho_relocation_info<P> reloc1;
-       macho_relocation_info<P> reloc2;
-       switch ( ref.getTarget().getDefinitionKind() ) {
-               case ObjectFile::Atom::kTentativeDefinition:
-               case ObjectFile::Atom::kRegularDefinition:
-               case ObjectFile::Atom::kWeakDefinition:
-                       switch ( ref.getKind() ) {
-                               case ppc::kAbsLow16:
-                               case ppc::kAbsLow14:
-                                       // a reference to the absolute address of something in this same linkage unit can be 
-                                       // encoded as a local text reloc in a dylib or bundle 
-                                       if ( fSlideable ) {
-                                               SectionInfo* sectInfo = (SectionInfo*)(ref.getTarget().getSection());
-                                               uint32_t targetAddr = ref.getTarget().getAddress() + ref.getTargetOffset();
-                                               reloc1.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
-                                               reloc1.set_r_symbolnum(sectInfo->getIndex());
-                                               reloc1.set_r_pcrel(false);
-                                               reloc1.set_r_length(2);
-                                               reloc1.set_r_extern(false);
-                                               reloc1.set_r_type(ref.getKind()==ppc::kAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
-                                               reloc2.set_r_address(targetAddr >> 16);
-                                               reloc2.set_r_symbolnum(0);
-                                               reloc2.set_r_pcrel(false);
-                                               reloc2.set_r_length(2);
-                                               reloc2.set_r_extern(false);
-                                               reloc2.set_r_type(PPC_RELOC_PAIR);
-                                               fInternalRelocs.push_back(reloc1);
-                                               fInternalRelocs.push_back(reloc2);
-                                               atomSection->fHasTextLocalRelocs = true;
-                                               return true;
-                                       }
-                                       break;
-                               case ppc::kAbsHigh16:
-                               case ppc::kAbsHigh16AddLow:
-                                       if ( fSlideable ) {
-                                               SectionInfo* sectInfo = (SectionInfo*)(ref.getTarget().getSection());
-                                               uint32_t targetAddr = ref.getTarget().getAddress() + ref.getTargetOffset();
-                                               reloc1.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
-                                               reloc1.set_r_symbolnum(sectInfo->getIndex());
-                                               reloc1.set_r_pcrel(false);
-                                               reloc1.set_r_length(2);
-                                               reloc1.set_r_extern(false);
-                                               reloc1.set_r_type(ref.getKind()==ppc::kAbsHigh16AddLow ? PPC_RELOC_HA16 : PPC_RELOC_HI16);
-                                               reloc2.set_r_address(targetAddr & 0xFFFF);
-                                               reloc2.set_r_symbolnum(0);
-                                               reloc2.set_r_pcrel(false);
-                                               reloc2.set_r_length(2);
-                                               reloc2.set_r_extern(false);
-                                               reloc2.set_r_type(PPC_RELOC_PAIR);
-                                               fInternalRelocs.push_back(reloc1);
-                                               fInternalRelocs.push_back(reloc2);
-                                               atomSection->fHasTextLocalRelocs = true;
-                                               return true;
-                                       }
-                       }
-                       break;
-               case ObjectFile::Atom::kExternalDefinition:
-               case ObjectFile::Atom::kExternalWeakDefinition:
-               case ObjectFile::Atom::kAbsoluteSymbol:
-                       return false;
-       }
-       return false;
-}
-
-template <>
-bool Writer<arm>::generatesLocalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
-{
-       if ( ref.getKind() == arm::kReadOnlyPointer ) {
-               switch ( ref.getTarget().getDefinitionKind() ) {
-                       case ObjectFile::Atom::kTentativeDefinition:
-                       case ObjectFile::Atom::kRegularDefinition:
-                       case ObjectFile::Atom::kWeakDefinition:
-                               // a reference to the absolute address of something in this same linkage unit can be 
-                               // encoded as a local text reloc in a dylib or bundle 
-                               if ( fSlideable ) {
-                                       macho_relocation_info<P> reloc;
-                                       SectionInfo* sectInfo = (SectionInfo*)(ref.getTarget().getSection());
-                                       reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
-                                       reloc.set_r_symbolnum(sectInfo->getIndex());
-                                       reloc.set_r_pcrel(false);
-                                       reloc.set_r_length();
-                                       reloc.set_r_extern(false);
-                                       reloc.set_r_type(GENERIC_RELOC_VANILLA);
-                                       fInternalRelocs.push_back(reloc);
-                                       atomSection->fHasTextLocalRelocs = true;
-                                       if ( fOptions.makeCompressedDyldInfo() ) {
-                                               fRebaseInfo.push_back(RebaseInfo(REBASE_TYPE_TEXT_ABSOLUTE32, atom.getAddress() + ref.getFixUpOffset()));
-                                       }
-                                       return true;
-                               }
-                               return false;
-                       case ObjectFile::Atom::kExternalDefinition:
-                       case ObjectFile::Atom::kExternalWeakDefinition:
-                       case ObjectFile::Atom::kAbsoluteSymbol:
-                               return false;
-               }
-       }
-       return false;
-}
-
-
-template <>
-bool Writer<x86_64>::generatesLocalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection)
-{
-       // text relocs not supported (usually never needed because of RIP addressing)
-       return false;
-}
-
-template <>
-bool Writer<ppc64>::generatesLocalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection)
-{
-       // text relocs not supported
-       return false;
-}
-
-template <>
-bool Writer<x86>::generatesExternalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
-{
-       if ( ref.getKind() == x86::kAbsolute32 ) {
-               macho_relocation_info<P> reloc;
-               switch ( ref.getTarget().getDefinitionKind() ) {
-                       case ObjectFile::Atom::kTentativeDefinition:
-                       case ObjectFile::Atom::kRegularDefinition:
-                       case ObjectFile::Atom::kWeakDefinition:
-                               return false;
-                       case ObjectFile::Atom::kExternalDefinition:
-                       case ObjectFile::Atom::kExternalWeakDefinition:
-                               // a reference to the absolute address of something in another linkage unit can be 
-                               // encoded as an external text reloc in a dylib or bundle 
-                               reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
-                               reloc.set_r_symbolnum(this->symbolIndex(ref.getTarget()));
-                               reloc.set_r_pcrel(false);
-                               reloc.set_r_length();
-                               reloc.set_r_extern(true);
-                               reloc.set_r_type(GENERIC_RELOC_VANILLA);
-                               fExternalRelocs.push_back(reloc);
-                               atomSection->fHasTextExternalRelocs = true;
-                               return true;
-                       case ObjectFile::Atom::kAbsoluteSymbol:
-                               return false;
-               }
-       }
-       return false;
-}
-
-template <>
-bool Writer<x86_64>::generatesExternalTextReloc(const ObjectFile::Reference& ref, const ObjectFile::Atom& atom, SectionInfo* atomSection)
-{
-       if ( fOptions.outputKind() == Options::kKextBundle ) {
-               macho_relocation_info<P> reloc;
-               switch ( ref.getTarget().getDefinitionKind() ) {
-                       case ObjectFile::Atom::kTentativeDefinition:
-                       case ObjectFile::Atom::kRegularDefinition:
-                       case ObjectFile::Atom::kWeakDefinition:
-                       case ObjectFile::Atom::kAbsoluteSymbol:
-                               return false;
-                       case ObjectFile::Atom::kExternalDefinition:
-                       case ObjectFile::Atom::kExternalWeakDefinition:
-                               switch ( ref.getKind() ) {
-                                       case x86_64::kBranchPCRel32:
-                                       case x86_64::kBranchPCRel32WeakImport:
-                                               // a branch to something in another linkage unit is
-                                               // encoded as an external text reloc in a kext bundle 
-                                               reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
-                                               reloc.set_r_symbolnum(this->symbolIndex(ref.getTarget()));
-                                               reloc.set_r_pcrel(true);
-                                               reloc.set_r_length(2);
-                                               reloc.set_r_extern(true);
-                                               reloc.set_r_type(X86_64_RELOC_BRANCH);
-                                               fExternalRelocs.push_back(reloc);
-                                               atomSection->fHasTextExternalRelocs = true;
-                                               return true;
-                                       case x86_64::kPCRel32GOTLoad:
-                                       case x86_64::kPCRel32GOTLoadWeakImport:
-                                               // a load of the GOT entry for a symbol in another linkage unit is 
-                                               // encoded as an external text reloc in a kext bundle 
-                                               reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
-                                               reloc.set_r_symbolnum(this->symbolIndex(ref.getTarget()));
-                                               reloc.set_r_pcrel(true);
-                                               reloc.set_r_length(2);
-                                               reloc.set_r_extern(true);
-                                               reloc.set_r_type(X86_64_RELOC_GOT_LOAD);
-                                               fExternalRelocs.push_back(reloc);
-                                               atomSection->fHasTextExternalRelocs = true;
-                                               return true;
-                                       case x86_64::kPCRel32GOT:
-                                       case x86_64::kPCRel32GOTWeakImport:
-                                               // a use of the GOT entry for a symbol in another linkage unit is 
-                                               // encoded as an external text reloc in a kext bundle 
-                                               reloc.set_r_address(this->relocAddressInFinalLinkedImage(atom.getAddress() + ref.getFixUpOffset(), &atom));
-                                               reloc.set_r_symbolnum(this->symbolIndex(ref.getTarget()));
-                                               reloc.set_r_pcrel(true);
-                                               reloc.set_r_length(2);
-                                               reloc.set_r_extern(true);
-                                               reloc.set_r_type(X86_64_RELOC_GOT);
-                                               fExternalRelocs.push_back(reloc);
-                                               atomSection->fHasTextExternalRelocs = true;
-                                               return true;
-                               }
-                               break;  
-               }
-       }
-       return false;
-}
-
-
-template <typename A>
-bool Writer<A>::generatesExternalTextReloc(const ObjectFile::Reference&, const ObjectFile::Atom& atom, SectionInfo* curSection)
-{
-       return false;
-}
-
-
-
-
-template <typename A>
-typename Writer<A>::RelocKind Writer<A>::relocationNeededInFinalLinkedImage(const ObjectFile::Atom& target) const
-{
-       switch ( target.getDefinitionKind() ) {
-               case ObjectFile::Atom::kTentativeDefinition:
-               case ObjectFile::Atom::kRegularDefinition:
-                       // in main executables, the only way regular symbols are indirected is if -interposable is used
-                       if ( fOptions.outputKind() == Options::kDynamicExecutable ) {
-                               if ( this->shouldExport(target) && fOptions.interposable(target.getName()) )
-                                       return kRelocExternal;
-                               else if ( fSlideable )
-                                       return kRelocInternal;
-                               else
-                                       return kRelocNone;
-                       }
-                       // for flat-namespace or interposable two-level-namespace
-                       // all references to exported symbols get indirected
-                       else if ( this->shouldExport(target) &&
-                          ((fOptions.nameSpace() == Options::kFlatNameSpace)
-                         || (fOptions.nameSpace() == Options::kForceFlatNameSpace)
-                         || fOptions.interposable(target.getName())) 
-                         && (target.getName() != NULL) 
-                         && (strncmp(target.getName(), ".objc_class_", 12) != 0) ) // <rdar://problem/5254468>
-                               return kRelocExternal;
-                       else if ( fSlideable )
-                               return kRelocInternal;
-                       else
-                               return kRelocNone;
-               case ObjectFile::Atom::kWeakDefinition:
-                       // in static executables, references to weak definitions are not indirected
-                       if ( fOptions.outputKind() == Options::kStaticExecutable)
-                               return kRelocNone;
-                       // in dynamic code, all calls to global weak definitions get indirected
-                       if ( this->shouldExport(target) )
-                               return kRelocExternal;
-                       else if ( fSlideable )
-                               return kRelocInternal;
-                       else
-                               return kRelocNone;
-               case ObjectFile::Atom::kExternalDefinition:
-               case ObjectFile::Atom::kExternalWeakDefinition:
-                       return kRelocExternal;
-               case ObjectFile::Atom::kAbsoluteSymbol:
-                       return kRelocNone;
-       }
-       return kRelocNone;
-}
-
-template <typename A>
-uint64_t Writer<A>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
-{
-       // for 32-bit architectures, the r_address field in relocs
-       // for final linked images is the offset from the first segment
-       uint64_t result = address - fSegmentInfos[0]->fBaseAddress;
-       if ( fOptions.outputKind() == Options::kPreload ) {
-               // kPreload uses a virtual __HEADER segment to cover the load commands
-               result = address - fSegmentInfos[1]->fBaseAddress;
-       }
-       // or the offset from the first writable segment if built split-seg
-       if ( fOptions.splitSeg() )
-               result = address - fFirstWritableSegment->fBaseAddress;
-       if ( result > 0x7FFFFFFF ) {
-               throwf("image too large: address can't fit in 31-bit r_address field in %s from %s",
-                       atom->getDisplayName(), atom->getFile()->getPath());
-       }
-       return result;
-}
-
-template <>
-uint64_t Writer<ppc64>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom)  const
-{
-       // for ppc64, the Mac OS X 10.4 dyld assumes r_address is always the offset from the base address.  
-       // the 10.5 dyld, iterprets the r_address as:
-       //   1) an offset from the base address, iff there are no writable segments with a address > 4GB from base address, otherwise
-       //   2) an offset from the base address of the first writable segment
-       // For dyld, r_address is always the offset from the base address
-       uint64_t result;
-       bool badFor10_4 = false;
-       if ( fWritableSegmentPastFirst4GB ) {
-               if ( fOptions.macosxVersionMin() < ObjectFile::ReaderOptions::k10_5 )
-                       badFor10_4 = true;
-               result = address - fFirstWritableSegment->fBaseAddress;
-               if ( result > 0xFFFFFFFF ) {
-                       throwf("image too large: address can't fit in 32-bit r_address field in %s from %s",
-                               atom->getDisplayName(), atom->getFile()->getPath());
-               }
-       }
-       else {
-               result = address - fSegmentInfos[0]->fBaseAddress;
-               if ( (fOptions.macosxVersionMin() < ObjectFile::ReaderOptions::k10_5) && (result > 0x7FFFFFFF) )
-                       badFor10_4 = true;
-       }
-       if ( badFor10_4 ) {
-                       throwf("image or pagezero_size too large for Mac OS X 10.4: address can't fit in 31-bit r_address field for %s from %s",
-                               atom->getDisplayName(), atom->getFile()->getPath());
-       }
-       return result;
-}
-
-
-template <> bool    Writer<ppc>::preboundLazyPointerType(uint8_t* type) { *type = PPC_RELOC_PB_LA_PTR; return true; }
-template <> bool  Writer<ppc64>::preboundLazyPointerType(uint8_t* type) { throw "prebinding not supported"; }
-template <> bool    Writer<x86>::preboundLazyPointerType(uint8_t* type) { *type = GENERIC_RELOC_PB_LA_PTR; return true; }
-template <> bool Writer<x86_64>::preboundLazyPointerType(uint8_t* type) { throw "prebinding not supported"; }
-template <> bool    Writer<arm>::preboundLazyPointerType(uint8_t* type) { *type = ARM_RELOC_PB_LA_PTR; return true; }
-
-template <typename A>
-void Writer<A>::buildExecutableFixups()
-{
-       if ( fIndirectTableAtom != NULL )
-               fIndirectTableAtom->fTable.reserve(50);  // minimize reallocations
-       std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
-       const int segCount = segmentInfos.size();
-       for(int i=0; i < segCount; ++i) {
-               SegmentInfo* curSegment = segmentInfos[i];
-               std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
-               const int sectionCount = sectionInfos.size();
-               for(int j=0; j < sectionCount; ++j) {
-                       SectionInfo* curSection = sectionInfos[j];
-                       //fprintf(stderr, "starting section %s\n", curSection->fSectionName);
-                       std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
-                       if ( ! curSection->fAllZeroFill ) {
-                               if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllLazyDylibPointers 
-                                                                                               || curSection->fAllStubs || curSection->fAllSelfModifyingStubs ) {
-                                       if ( fIndirectTableAtom != NULL )
-                                               curSection->fIndirectSymbolOffset = fIndirectTableAtom->fTable.size();
-                               }
-                               const int atomCount = sectionAtoms.size();
-                               for (int k=0; k < atomCount; ++k) {
-                                       ObjectFile::Atom* atom = sectionAtoms[k];
-                                       std::vector<ObjectFile::Reference*>& refs = atom->getReferences();
-                                       const int refCount = refs.size();
-                                       //fprintf(stderr, "atom %s has %d references in section %s, %p\n", atom->getDisplayName(), refCount, curSection->fSectionName, atom->getSection());
-                                       if ( curSection->fAllNonLazyPointers && (refCount == 0) ) {
-                                               // handle imageloadercache GOT slot
-                                               uint32_t offsetInSection = atom->getSectionOffset();
-                                               uint32_t indexInSection = offsetInSection / sizeof(pint_t);
-                                               uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
-                                               // use INDIRECT_SYMBOL_ABS so 10.5 dyld will leave value as zero
-                                               IndirectEntry entry = { indirectTableIndex, INDIRECT_SYMBOL_ABS };
-                                               //fprintf(stderr,"fIndirectTableAtom->fTable.push_back(tableIndex=%d, symIndex=0x%X, section=%s)\n", 
-                                               //              indirectTableIndex, INDIRECT_SYMBOL_LOCAL, curSection->fSectionName);
-                                               fIndirectTableAtom->fTable.push_back(entry);
-                                       }
-                                       for (int l=0; l < refCount; ++l) {
-                                               ObjectFile::Reference* ref = refs[l];
-                                               if ( (fOptions.outputKind() != Options::kKextBundle) && 
-                                                               (curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllLazyDylibPointers) ) {
-                                                       // if atom is in (non)lazy_pointer section, this is encoded as an indirect symbol
-                                                       if ( atom->getSize() != sizeof(pint_t) ) {
-                                                               warning("wrong size pointer atom %s from file %s", atom->getDisplayName(), atom->getFile()->getPath());
-                                                       }
-                                                       ObjectFile::Atom* pointerTarget = &(ref->getTarget());
-                                                       if ( curSection->fAllLazyPointers || curSection->fAllLazyDylibPointers ) {
-                                                               pointerTarget = ((LazyPointerAtom<A>*)atom)->getTarget();
-                                                       }
-                                                       uint32_t offsetInSection = atom->getSectionOffset();
-                                                       uint32_t indexInSection = offsetInSection / sizeof(pint_t);
-                                                       uint32_t undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
-                                                       if  (atom == fFastStubGOTAtom)
-                                                               undefinedSymbolIndex = INDIRECT_SYMBOL_ABS;
-                                                       else if ( this->relocationNeededInFinalLinkedImage(*pointerTarget) == kRelocExternal )
-                                                               undefinedSymbolIndex = this->symbolIndex(*pointerTarget);
-                                                       uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
-                                                       IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
-                                                       //fprintf(stderr,"fIndirectTableAtom->fTable.push_back(tableIndex=%d, symIndex=0x%X, section=%s)\n", 
-                                                       //              indirectTableIndex, undefinedSymbolIndex, curSection->fSectionName);
-                                                       fIndirectTableAtom->fTable.push_back(entry);
-                                                       if ( curSection->fAllLazyPointers || curSection->fAllLazyDylibPointers ) {
-                                                               uint8_t preboundLazyType;
-                                                               if ( fOptions.prebind() && (fDyldClassicHelperAtom != NULL) 
-                                                                               && curSection->fAllLazyPointers && preboundLazyPointerType(&preboundLazyType) ) {
-                                                                       // this is a prebound image, need special relocs for dyld to reset lazy pointers if prebinding is invalid
-                                                                       macho_scattered_relocation_info<P> pblaReloc;
-                                                                       pblaReloc.set_r_scattered(true);
-                                                                       pblaReloc.set_r_pcrel(false);
-                                                                       pblaReloc.set_r_length();
-                                                                       pblaReloc.set_r_type(preboundLazyType);
-                                                                       pblaReloc.set_r_address(relocAddressInFinalLinkedImage(atom->getAddress(), atom));
-                                                                       pblaReloc.set_r_value(fDyldClassicHelperAtom->getAddress());
-                                                                       fInternalRelocs.push_back(*((macho_relocation_info<P>*)&pblaReloc));
-                                                               }
-                                                               else if ( fSlideable ) {
-                                                                       // this is a non-prebound dylib/bundle, need vanilla internal relocation to fix up binding handler if image slides
-                                                                       macho_relocation_info<P> dyldHelperReloc;
-                                                                       uint32_t sectionNum = 1;
-                                                                       if ( fDyldClassicHelperAtom != NULL )
-                                                                               sectionNum = ((SectionInfo*)(fDyldClassicHelperAtom->getSection()))->getIndex();
-                                                                       //fprintf(stderr, "lazy pointer reloc, section index=%u, section name=%s\n", sectionNum, curSection->fSectionName);
-                                                                       dyldHelperReloc.set_r_address(relocAddressInFinalLinkedImage(atom->getAddress(), atom));
-                                                                       dyldHelperReloc.set_r_symbolnum(sectionNum);
-                                                                       dyldHelperReloc.set_r_pcrel(false);
-                                                                       dyldHelperReloc.set_r_length();
-                                                                       dyldHelperReloc.set_r_extern(false);
-                                                                       dyldHelperReloc.set_r_type(GENERIC_RELOC_VANILLA);
-                                                                       fInternalRelocs.push_back(dyldHelperReloc);
-                                                                       if ( fOptions.makeCompressedDyldInfo() ) {
-                                                                               fRebaseInfo.push_back(RebaseInfo(REBASE_TYPE_POINTER,atom->getAddress()));
-                                                                       }
-                                                               }
-                                                               if ( fOptions.makeCompressedDyldInfo() ) {
-                                                                       uint8_t type = BIND_TYPE_POINTER;
-                                                                       uint64_t addresss = atom->getAddress() + ref->getFixUpOffset();
-                                                                       if ( pointerTarget->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition ) {
-                                                                               // This is a referece to a weak def in some dylib (e.g. operator new)
-                                                                               // need to bind into to directly bind this
-                                                                               // later weak binding info may override
-                                                                               int ordinal = compressedOrdinalForImortedAtom(pointerTarget);
-                                                                               fBindingInfo.push_back(BindingInfo(type, ordinal, pointerTarget->getName(), false, addresss, 0));
-                                                                       }
-                                                                       if ( targetRequiresWeakBinding(*pointerTarget) ) {
-                                                                               // note: lazy pointers to weak symbols are not bound lazily
-                                                                               fWeakBindingInfo.push_back(BindingInfo(type, pointerTarget->getName(), false, addresss, 0));
-                                                                       }
-                                                               }
-                                                       }
-                                                       if ( curSection->fAllNonLazyPointers && fOptions.makeCompressedDyldInfo() ) {
-                                                               if ( pointerTarget != NULL ) {
-                                                                       switch ( this->relocationNeededInFinalLinkedImage(*pointerTarget) ) {
-                                                                               case kRelocNone:
-                                                                               // no rebase or binding info needed
-                                                                               break;
-                                                                               case kRelocInternal:
-                                                                                       // a non-lazy pointer that has been optimized to LOCAL needs rebasing info
-                                                                                       // but not the magic fFastStubGOTAtom atom
-                                                                                       if  (atom != fFastStubGOTAtom)
-                                                                                               fRebaseInfo.push_back(RebaseInfo(REBASE_TYPE_POINTER,atom->getAddress()));
-                                                                                       break;
-                                                                               case kRelocExternal:
-                                                                               {
-                                                                                       uint8_t type = BIND_TYPE_POINTER;
-                                                                                       uint64_t addresss = atom->getAddress();
-                                                                                       if ( targetRequiresWeakBinding(ref->getTarget()) ) {
-                                                                                               fWeakBindingInfo.push_back(BindingInfo(type, ref->getTarget().getName(), false, addresss, 0));
-                                                                                               // if this is a non-lazy pointer to a weak definition within this linkage unit
-                                                                                               // the pointer needs to initially point within linkage unit and have
-                                                                                               // rebase command to slide it.
-                                                                                               if ( ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kWeakDefinition ) {
-                                                                                                       // unless if this is a hybrid format, in which case the non-lazy pointer
-                                                                                                       // is zero on disk.  So use a bind instead of a rebase to set initial value
-                                                                                                       if ( fOptions.makeClassicDyldInfo() )
-                                                                                                               fBindingInfo.push_back(BindingInfo(type, BIND_SPECIAL_DYLIB_SELF, ref->getTarget().getName(), false, addresss, 0));
-                                                                                                       else
-                                                                                                               fRebaseInfo.push_back(RebaseInfo(REBASE_TYPE_POINTER,atom->getAddress()));
-                                                                                               }
-                                                                                               // if this is a non-lazy pointer to a weak definition in a dylib,
-                                                                                               // the pointer needs to initially bind to the dylib
-                                                                                               else if ( ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition ) {
-                                                                                                       int ordinal = compressedOrdinalForImortedAtom(pointerTarget);
-                                                                                                       fBindingInfo.push_back(BindingInfo(BIND_TYPE_POINTER, ordinal, pointerTarget->getName(), false, addresss, 0));
-                                                                                               }
-                                                                                       }
-                                                                                       else {
-                                                                                               int ordinal = compressedOrdinalForImortedAtom(pointerTarget);
-                                                                                               bool weak_import = fWeakImportMap[pointerTarget];
-                                                                                               fBindingInfo.push_back(BindingInfo(type, ordinal, ref->getTarget().getName(), weak_import, addresss, 0));
-                                                                                       }
-                                                                               }
-                                                                       }
-                                                               }
-                                                       }
-                                               }
-                                               else if ( (ref->getKind() == A::kPointer) || (ref->getKind() == A::kPointerWeakImport) ) {
-                                                       if ( fSlideable && ((curSegment->fInitProtection & VM_PROT_WRITE) == 0) ) {
-                                                               if ( fOptions.allowTextRelocs() ) {
-                                                                       if ( fOptions.warnAboutTextRelocs() )
-                                                                               warning("text reloc in %s to %s", atom->getDisplayName(), ref->getTargetName());
-                                                               }
-                                                               else {
-                                                                       throwf("pointer in read-only segment not allowed in slidable image, used in %s from %s",
-                                                                               atom->getDisplayName(), atom->getFile()->getPath());
-                                                               }
-                                                       }
-                                                       switch ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) ) {
-                                                               case kRelocNone:
-                                                                       // no reloc needed
-                                                                       break;
-                                                               case kRelocInternal:
-                                                                       {
-                                                                               macho_relocation_info<P> internalReloc;
-                                                                               SectionInfo* sectInfo = (SectionInfo*)ref->getTarget().getSection();
-                                                                               uint32_t sectionNum = sectInfo->getIndex();
-                                                                               // special case _mh_dylib_header and friends which are not in any real section
-                                                                               if ( (sectionNum ==0) && sectInfo->fVirtualSection && (strcmp(sectInfo->fSectionName, "._mach_header") == 0) )
-                                                                                       sectionNum = 1;
-                                                                               internalReloc.set_r_address(this->relocAddressInFinalLinkedImage(atom->getAddress() + ref->getFixUpOffset(), atom));
-                                                                               internalReloc.set_r_symbolnum(sectionNum);
-                                                                               internalReloc.set_r_pcrel(false);
-                                                                               internalReloc.set_r_length();
-                                                                               internalReloc.set_r_extern(false);
-                                                                               internalReloc.set_r_type(GENERIC_RELOC_VANILLA);
-                                                                               fInternalRelocs.push_back(internalReloc);
-                                                                               if ( fOptions.makeCompressedDyldInfo() ) {
-                                                                                       fRebaseInfo.push_back(RebaseInfo(REBASE_TYPE_POINTER, atom->getAddress() + ref->getFixUpOffset()));
-                                                                               }
-                                                                       }
-                                                                       break;
-                                                               case kRelocExternal:
-                                                                       {
-                                                                               macho_relocation_info<P> externalReloc;
-                                                                               externalReloc.set_r_address(this->relocAddressInFinalLinkedImage(atom->getAddress() + ref->getFixUpOffset(), atom));
-                                                                               externalReloc.set_r_symbolnum(this->symbolIndex(ref->getTarget()));
-                                                                               externalReloc.set_r_pcrel(false);
-                                                                               externalReloc.set_r_length();
-                                                                               externalReloc.set_r_extern(true);
-                                                                               externalReloc.set_r_type(GENERIC_RELOC_VANILLA);
-                                                                               fExternalRelocs.push_back(externalReloc);
-                                                                               if ( fOptions.makeCompressedDyldInfo() ) {
-                                                                                       int64_t addend = ref->getTargetOffset();
-                                                                                       uint64_t addresss = atom->getAddress() + ref->getFixUpOffset();
-                                                                                       if ( !fOptions.makeClassicDyldInfo() ) {
-                                                                                               if ( ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kWeakDefinition ) {
-                                                                                                       // pointers to internal weak defs need a rebase
-                                                                                                       fRebaseInfo.push_back(RebaseInfo(REBASE_TYPE_POINTER, addresss));
-                                                                                               }
-                                                                                       }
-                                                                                       uint8_t type = BIND_TYPE_POINTER;
-                                                                                       if ( targetRequiresWeakBinding(ref->getTarget()) ) {
-                                                                                               fWeakBindingInfo.push_back(BindingInfo(type, ref->getTarget().getName(), false, addresss, addend));
-                                                                                               if ( fOptions.makeClassicDyldInfo() && (ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kWeakDefinition) ) {
-                                                                                                       // hybrid linkedit puts addend in data, so we need bind phase to reset pointer to local definifion
-                                                                                                       fBindingInfo.push_back(BindingInfo(type, BIND_SPECIAL_DYLIB_SELF, ref->getTarget().getName(), false, addresss, addend));
-                                                                                               }
-                                                                                               // if this is a pointer to a weak definition in a dylib,
-                                                                                               // the pointer needs to initially bind to the dylib
-                                                                                               else if ( ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition ) {
-                                                                                                       int ordinal = compressedOrdinalForImortedAtom(&ref->getTarget());
-                                                                                                       fBindingInfo.push_back(BindingInfo(BIND_TYPE_POINTER, ordinal, ref->getTarget().getName(), false, addresss, addend));
-                                                                                               }
-                                                                                       }
-                                                                                       else {
-                                                                                               int ordinal = compressedOrdinalForImortedAtom(&ref->getTarget());
-                                                                                               bool weak_import = fWeakImportMap[&(ref->getTarget())];
-                                                                                               fBindingInfo.push_back(BindingInfo(type, ordinal, ref->getTarget().getName(), weak_import, addresss, addend));
-                                                                                       }
-                                                                               }
-                                                                       }
-                                                                       break;
-                                                       }
-                                               }
-                                               else if ( this->illegalRelocInFinalLinkedImage(*ref) ) {
-                                                       // new x86 stubs always require text relocs
-                                                       if ( curSection->fAllStubs || curSection->fAllStubHelpers ) {
-                                                               if ( this->generatesLocalTextReloc(*ref, *atom, curSection) ) {
-                                                                       // relocs added to fInternalRelocs
-                                                               }
-                                                       }
-                                                       else if ( fOptions.allowTextRelocs() && !atom->getSegment().isContentWritable() ) {
-                                                               if ( fOptions.warnAboutTextRelocs() )
-                                                                       warning("text reloc in %s to %s", atom->getDisplayName(), ref->getTargetName());
-                                                               if (  this->generatesLocalTextReloc(*ref, *atom, curSection) ) {
-                                                                       // relocs added to fInternalRelocs
-                                                               }
-                                                               else if ( this->generatesExternalTextReloc(*ref, *atom, curSection) ) {
-                                                                       // relocs added to fExternalRelocs
-                                                               }
-                                                               else {
-                                                                       throwf("relocation used in %s from %s not allowed in slidable image", atom->getDisplayName(), atom->getFile()->getPath());
-                                                               }
-                                                       }
-                                                       else {
-                                                               throwf("absolute addressing (perhaps -mdynamic-no-pic) used in %s from %s not allowed in slidable image. "
-                                                                               "Use '-read_only_relocs suppress' to enable text relocs", atom->getDisplayName(), atom->getFile()->getPath());
-                                                       }
-                                               }
-                                       }
-                                       if ( curSection->fAllSelfModifyingStubs || curSection->fAllStubs ) {
-                                               ObjectFile::Atom* stubTarget = ((StubAtom<A>*)atom)->getTarget();
-                                               uint32_t undefinedSymbolIndex = (stubTarget != NULL) ? this->symbolIndex(*stubTarget) : INDIRECT_SYMBOL_ABS;
-                                               uint32_t offsetInSection = atom->getSectionOffset();
-                                               uint32_t indexInSection = offsetInSection / atom->getSize();
-                                               uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
-                                               IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
-                                               //fprintf(stderr,"for stub: fIndirectTableAtom->fTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, stubTarget->getName(), atom->getSize());
-                                               fIndirectTableAtom->fTable.push_back(entry);
-                                       }
-                               }
-                       }
-               }
-       }
-       if ( fSplitCodeToDataContentAtom != NULL )
-               fSplitCodeToDataContentAtom->encode();
-       if ( fCompressedRebaseInfoAtom != NULL ) 
-               fCompressedRebaseInfoAtom->encode();
-       if ( fCompressedBindingInfoAtom != NULL ) 
-               fCompressedBindingInfoAtom->encode();
-       if ( fCompressedWeakBindingInfoAtom != NULL ) 
-               fCompressedWeakBindingInfoAtom->encode();
-       if ( fCompressedLazyBindingInfoAtom != NULL ) 
-               fCompressedLazyBindingInfoAtom->encode();
-       if ( fCompressedExportInfoAtom != NULL ) 
-               fCompressedExportInfoAtom->encode();
-}
-
-
-template <>
-void Writer<ppc>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
-{
-       switch ( (ppc::ReferenceKinds)ref->getKind() ) {
-               case ppc::kPICBaseHigh16:
-                       fSplitCodeToDataContentAtom->addPPCHi16Location(atom, ref->getFixUpOffset());
-                       break;
-               case ppc::kPointerDiff32:
-                       fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
-                       break;
-               case ppc::kPointerDiff64:
-                       fSplitCodeToDataContentAtom->add64bitPointerLocation(atom, ref->getFixUpOffset());
-                       break;
-               case ppc::kNoFixUp:
-               case ppc::kGroupSubordinate:
-               case ppc::kPointer:
-               case ppc::kPointerWeakImport:
-               case ppc::kPICBaseLow16:
-               case ppc::kPICBaseLow14:
-                       // ignore
-                       break;
-               default:
-                       warning("codegen with reference kind %d in %s prevents image from loading in dyld shared cache", ref->getKind(), atom->getDisplayName());
-                       fSplitCodeToDataContentAtom->setCantEncode();
-       }
-}
-
-template <>
-void Writer<ppc64>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
-{
-       switch ( (ppc64::ReferenceKinds)ref->getKind()  ) {
-               case ppc64::kPICBaseHigh16:
-                       fSplitCodeToDataContentAtom->addPPCHi16Location(atom, ref->getFixUpOffset());
-                       break;
-               case ppc64::kPointerDiff32:
-                       fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
-                       break;
-               case ppc64::kPointerDiff64:
-                       fSplitCodeToDataContentAtom->add64bitPointerLocation(atom, ref->getFixUpOffset());
-                       break;
-               case ppc64::kNoFixUp:
-               case ppc64::kGroupSubordinate:
-               case ppc64::kPointer:
-               case ppc64::kPointerWeakImport:
-               case ppc64::kPICBaseLow16:
-               case ppc64::kPICBaseLow14:
-                       // ignore
-                       break;
-               default:
-                       warning("codegen with reference kind %d in %s prevents image from loading in dyld shared cache", ref->getKind(), atom->getDisplayName());
-                       fSplitCodeToDataContentAtom->setCantEncode();
-       }
-}
-
-template <>
-void Writer<x86>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
-{
-       switch ( (x86::ReferenceKinds)ref->getKind()  ) {
-               case x86::kPointerDiff:
-               case x86::kImageOffset32:
-                       if ( strcmp(ref->getTarget().getSegment().getName(), "__IMPORT") == 0 ) 
-                               fSplitCodeToDataContentAtom->add32bitImportLocation(atom, ref->getFixUpOffset());
-                       else
-                               fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
-                       break;
-               case x86::kNoFixUp:
-               case x86::kGroupSubordinate:
-               case x86::kPointer:
-               case x86::kPointerWeakImport:
-                       // ignore
-                       break;
-               case x86::kPCRel32:
-               case x86::kPCRel32WeakImport:
-                       if (    (&(ref->getTarget().getSegment()) == &Segment::fgImportSegment)
-                               ||  (&(ref->getTarget().getSegment()) == &Segment::fgROImportSegment) ) {
-                               fSplitCodeToDataContentAtom->add32bitImportLocation(atom, ref->getFixUpOffset());
-                               break;
-                       }
-                       // fall into warning case
-               default:
-                       if ( fOptions.makeCompressedDyldInfo() && (ref->getKind() == x86::kAbsolute32) ) {
-                               // will be encoded in rebase info
-                       }
-                       else {
-                               warning("codegen in %s (offset 0x%08llX) prevents image from loading in dyld shared cache", atom->getDisplayName(), ref->getFixUpOffset());
-                               fSplitCodeToDataContentAtom->setCantEncode();
-                       }
-       }
-}
-
-template <>
-void Writer<x86_64>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
-{
-       switch ( (x86_64::ReferenceKinds)ref->getKind()  ) {
-               case x86_64::kPCRel32:
-               case x86_64::kPCRel32_1:
-               case x86_64::kPCRel32_2:
-               case x86_64::kPCRel32_4:
-               case x86_64::kPCRel32GOTLoad:
-               case x86_64::kPCRel32GOTLoadWeakImport:
-               case x86_64::kPCRel32GOT:
-               case x86_64::kPCRel32GOTWeakImport:
-               case x86_64::kPointerDiff32:
-               case x86_64::kImageOffset32:
-                       fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
-                       break;
-               case x86_64::kPointerDiff:
-                       fSplitCodeToDataContentAtom->add64bitPointerLocation(atom, ref->getFixUpOffset());
-                       break;
-               case x86_64::kNoFixUp:
-               case x86_64::kGroupSubordinate:
-               case x86_64::kPointer:
-               case x86_64::kGOTNoFixUp:
-                       // ignore
-                       break;
-               default:
-                       warning("codegen in %s with kind %d prevents image from loading in dyld shared cache", atom->getDisplayName(), ref->getKind());
-                       fSplitCodeToDataContentAtom->setCantEncode();
-       }
-}
-
-template <>
-void Writer<arm>::addCrossSegmentRef(const ObjectFile::Atom* atom, const ObjectFile::Reference* ref)
-{
-       switch ( (arm::ReferenceKinds)ref->getKind()  ) {
-               case arm::kPointerDiff:
-                       fSplitCodeToDataContentAtom->add32bitPointerLocation(atom, ref->getFixUpOffset());
-                       break;
-               case arm::kNoFixUp:
-               case arm::kGroupSubordinate:
-               case arm::kPointer:
-               case arm::kPointerWeakImport:
-               case arm::kReadOnlyPointer:
-                       // ignore
-                       break;
-               default:
-                       warning("codegen in %s prevents image from loading in dyld shared cache", atom->getDisplayName());
-                       fSplitCodeToDataContentAtom->setCantEncode();
-       }
-}
-
-template <typename A>
-bool Writer<A>::segmentsCanSplitApart(const ObjectFile::Atom& from, const ObjectFile::Atom& to)
-{
-       switch ( to.getDefinitionKind() ) {
-               case ObjectFile::Atom::kExternalDefinition:
-               case ObjectFile::Atom::kExternalWeakDefinition:
-               case ObjectFile::Atom::kAbsoluteSymbol:
-                       return false;
-               case ObjectFile::Atom::kRegularDefinition:
-               case ObjectFile::Atom::kWeakDefinition:
-               case ObjectFile::Atom::kTentativeDefinition:
-                       // segments with same permissions slide together
-                       return ( (from.getSegment().isContentExecutable() != to.getSegment().isContentExecutable())
-                                       || (from.getSegment().isContentWritable() != to.getSegment().isContentWritable()) );
-       }
-       throw "ld64 internal error";
-}
-
-
-template <>
-void Writer<ppc>::writeNoOps(int fd, uint32_t from, uint32_t to)
-{
-       uint32_t ppcNop;
-       OSWriteBigInt32(&ppcNop, 0, 0x60000000);
-       for (uint32_t p=from; p < to; p += 4)
-               ::pwrite(fd, &ppcNop, 4, p);
-}
-
-template <>
-void Writer<ppc64>::writeNoOps(int fd, uint32_t from, uint32_t to)
-{
-       uint32_t ppcNop;
-       OSWriteBigInt32(&ppcNop, 0, 0x60000000);
-       for (uint32_t p=from; p < to; p += 4)
-               ::pwrite(fd, &ppcNop, 4, p);
-}
-
-template <>
-void Writer<x86>::writeNoOps(int fd, uint32_t from, uint32_t to)
-{
-       uint8_t x86Nop = 0x90;
-       for (uint32_t p=from; p < to; ++p)
-               ::pwrite(fd, &x86Nop, 1, p);
-}
-
-template <>
-void Writer<x86_64>::writeNoOps(int fd, uint32_t from, uint32_t to)
-{
-       uint8_t x86Nop = 0x90;
-       for (uint32_t p=from; p < to; ++p)
-               ::pwrite(fd, &x86Nop, 1, p);
-}
-
-template <>
-void Writer<arm>::writeNoOps(int fd, uint32_t from, uint32_t to)
-{
-       // FIXME: need thumb nop?
-       uint32_t armNop;
-       OSWriteLittleInt32(&armNop, 0, 0xe1a00000);
-       for (uint32_t p=from; p < to; p += 4)
-               ::pwrite(fd, &armNop, 4, p);
-}
-
-template <>
-void Writer<ppc>::copyNoOps(uint8_t* from, uint8_t* to)
-{
-       for (uint8_t* p=from; p < to; p += 4)
-               OSWriteBigInt32((uint32_t*)p, 0, 0x60000000);
-}
-
-template <>
-void Writer<ppc64>::copyNoOps(uint8_t* from, uint8_t* to)
-{
-       for (uint8_t* p=from; p < to; p += 4)
-               OSWriteBigInt32((uint32_t*)p, 0, 0x60000000);
-}
-
-template <>
-void Writer<x86>::copyNoOps(uint8_t* from, uint8_t* to)
-{
-       for (uint8_t* p=from; p < to; ++p)
-               *p = 0x90;
-}
-
-template <>
-void Writer<x86_64>::copyNoOps(uint8_t* from, uint8_t* to)
-{
-       for (uint8_t* p=from; p < to; ++p)
-               *p = 0x90;
-}
-
-template <>
-void Writer<arm>::copyNoOps(uint8_t* from, uint8_t* to)
-{
-    // fixme: need thumb nop?
-       for (uint8_t* p=from; p < to; p += 4)
-               OSWriteBigInt32((uint32_t*)p, 0, 0xe1a00000);
-}
-
-static const char* stringName(const char* str)
-{
-       if ( strncmp(str, "cstring=", 8) == 0)  {
-               static char buffer[1024];
-               char* t = buffer;
-               *t++ = '\"';
-               for(const char*s = &str[8]; *s != '\0'; ++s) {
-                       switch(*s) {
-                               case '\n':
-                                       *t++ = '\\';
-                                       *t++ = 'n';
-                                       break;
-                               case '\t':
-                                       *t++ = '\\';
-                                       *t++ = 't';
-                                       break;
-                               default:
-                                       *t++ = *s;
-                                       break;
-                       }
-                       if ( t > &buffer[1020] ) {
-                               *t++= '\"';
-                               *t++= '.';
-                               *t++= '.';
-                               *t++= '.';
-                               *t++= '\0';
-                               return buffer;
-                       }
-               }
-               *t++= '\"';
-               *t++= '\0';
-               return buffer;
-       }
-       else {
-               return str;
-       }
-}
-
-
-template <> const char* Writer<ppc>::getArchString()    { return "ppc"; }
-template <> const char* Writer<ppc64>::getArchString()  { return "ppc64"; }
-template <> const char* Writer<x86>::getArchString()    { return "i386"; }
-template <> const char* Writer<x86_64>::getArchString() { return "x86_64"; }
-template <> const char* Writer<arm>::getArchString()    { return "arm"; }
-
-template <typename A>
-void Writer<A>::writeMap()
-{
-       if ( fOptions.generatedMapPath() != NULL ) {
-               FILE* mapFile = fopen(fOptions.generatedMapPath(), "w"); 
-               if ( mapFile != NULL ) {
-                       // write output path
-                       fprintf(mapFile, "# Path: %s\n", fFilePath);
-                       // write output architecure
-                       fprintf(mapFile, "# Arch: %s\n", getArchString());
-                       // write UUID
-                       if ( fUUIDAtom != NULL ) {
-                               const uint8_t* uuid = fUUIDAtom->getUUID();
-                               fprintf(mapFile, "# UUID: %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X \n",
-                                       uuid[0], uuid[1], uuid[2],  uuid[3],  uuid[4],  uuid[5],  uuid[6],  uuid[7],
-                                       uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
-                       }
-                       // write table of object files
-                       std::map<ObjectFile::Reader*, uint32_t> readerToOrdinal;
-                       std::map<uint32_t, ObjectFile::Reader*> ordinalToReader;
-                       std::map<ObjectFile::Reader*, uint32_t> readerToFileOrdinal;
-                       for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
-                               std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
-                               for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
-                                       if ( ! (*secit)->fVirtualSection ) {
-                                               std::vector<ObjectFile::Atom*>& sectionAtoms = (*secit)->fAtoms;
-                                               for (std::vector<ObjectFile::Atom*>::iterator ait = sectionAtoms.begin(); ait != sectionAtoms.end(); ++ait) {
-                                                       ObjectFile::Reader* reader = (*ait)->getFile();
-                                                       uint32_t readerOrdinal = (*ait)->getOrdinal();
-                                                       std::map<ObjectFile::Reader*, uint32_t>::iterator pos = readerToOrdinal.find(reader);
-                                                       if ( pos == readerToOrdinal.end() ) {
-                                                               readerToOrdinal[reader] = readerOrdinal;
-                                                               ordinalToReader[readerOrdinal] = reader;
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-                       fprintf(mapFile, "# Object files:\n");
-                       fprintf(mapFile, "[%3u] %s\n", 0, "linker synthesized");
-                       uint32_t fileIndex = 0;
-                       readerToFileOrdinal[this] = fileIndex++;
-                       for(std::map<uint32_t, ObjectFile::Reader*>::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) {
-                               if ( it->first != 0 ) {
-                                       fprintf(mapFile, "[%3u] %s\n", fileIndex, it->second->getPath());
-                                       readerToFileOrdinal[it->second] = fileIndex++;
-                               }
-                       }
-                       // write table of sections
-                       fprintf(mapFile, "# Sections:\n");
-                       fprintf(mapFile, "# Address\tSize    \tSegment\tSection\n"); 
-                       for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
-                               std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
-                               for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
-                                       if ( ! (*secit)->fVirtualSection ) {
-                                               SectionInfo* sect = *secit;
-                                               fprintf(mapFile, "0x%08llX\t0x%08llX\t%s\t%s\n", sect->getBaseAddress(), sect->fSize, 
-                                                       (*segit)->fName, sect->fSectionName);
-                                       }
-                               }
-                       }
-                       // write table of symbols
-                       fprintf(mapFile, "# Symbols:\n");
-                       fprintf(mapFile, "# Address\tSize    \tFile  Name\n"); 
-                       for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
-                               std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
-                               for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
-                                       if ( ! (*secit)->fVirtualSection ) {
-                                               std::vector<ObjectFile::Atom*>& sectionAtoms = (*secit)->fAtoms;
-                                               bool isCstring = (strcmp((*secit)->fSectionName, "__cstring") == 0);
-                                               for (std::vector<ObjectFile::Atom*>::iterator ait = sectionAtoms.begin(); ait != sectionAtoms.end(); ++ait) {
-                                                       ObjectFile::Atom* atom = *ait;
-                                                       fprintf(mapFile, "0x%08llX\t0x%08llX\t[%3u] %s\n", atom->getAddress(), atom->getSize(), 
-                                                               readerToFileOrdinal[atom->getFile()], isCstring ? stringName(atom->getDisplayName()): atom->getDisplayName());
-                                               }
-                                       }
-                               }
-                       }
-                       fclose(mapFile);
-               }
-               else {
-                       warning("could not write map file: %s\n", fOptions.generatedMapPath());
-               }
-       }
-}
-
-static const char* sCleanupFile = NULL;
-static void cleanup(int sig)
-{
-       ::signal(sig, SIG_DFL);
-       if ( sCleanupFile != NULL ) {
-               ::unlink(sCleanupFile);
-       }
-       if ( sig == SIGINT )
-               ::exit(1);
-}
-
-
-template <typename A>
-uint64_t Writer<A>::writeAtoms()
-{
-       // for UNIX conformance, error if file exists and is not writable
-       if ( (access(fFilePath, F_OK) == 0) && (access(fFilePath, W_OK) == -1) )
-               throwf("can't write output file: %s", fFilePath);
-
-       int permissions = 0777;
-       if ( fOptions.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 fFilePath 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)
-       (void)unlink(fFilePath);
-       
-       // try to allocate buffer for entire output file content
-       int fd = -1;
-       SectionInfo* lastSection = fSegmentInfos.back()->fSections.back();
-       uint64_t fileBufferSize = (lastSection->fFileOffset + lastSection->fSize + 4095) & (-4096);
-       uint8_t* wholeBuffer = (uint8_t*)calloc(fileBufferSize, 1);
-       uint8_t* atomBuffer = NULL;
-       bool streaming = false;
-       if ( wholeBuffer == NULL ) {
-               fd = open(fFilePath, O_CREAT | O_WRONLY | O_TRUNC, permissions);
-               if ( fd == -1 ) 
-                       throwf("can't open output file for writing: %s, errno=%d", fFilePath, errno);
-               atomBuffer = new uint8_t[(fLargestAtomSize+4095) & (-4096)];
-               streaming = true;
-               // install signal handlers to delete output file if program is killed 
-               sCleanupFile = fFilePath;
-               ::signal(SIGINT, cleanup);
-               ::signal(SIGBUS, cleanup);
-               ::signal(SIGSEGV, cleanup);
-       }
-       uint32_t size = 0;
-       uint32_t end = 0;
-       try {
-               for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
-                       SegmentInfo* curSegment = *segit;
-                       std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
-                       for (std::vector<SectionInfo*>::iterator secit = sectionInfos.begin(); secit != sectionInfos.end(); ++secit) {
-                               SectionInfo* curSection = *secit;
-                               std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
-                               //printf("writing with max atom size 0x%X\n", fLargestAtomSize);
-                               //fprintf(stderr, "writing %lu atoms for section %p %s at file offset 0x%08llX\n", sectionAtoms.size(), curSection, curSection->fSectionName, curSection->fFileOffset);
-                               if ( ! curSection->fAllZeroFill ) {
-                                       bool needsNops = ((strcmp(curSection->fSegmentName, "__TEXT") == 0) && (strncmp(curSection->fSectionName, "__text", 6) == 0));
-                                       for (std::vector<ObjectFile::Atom*>::iterator ait = sectionAtoms.begin(); ait != sectionAtoms.end(); ++ait) {
-                                               ObjectFile::Atom* atom = *ait;
-                                               if ( (atom->getDefinitionKind() != ObjectFile::Atom::kExternalDefinition)
-                                                 && (atom->getDefinitionKind() != ObjectFile::Atom::kExternalWeakDefinition)
-                                                 && (atom->getDefinitionKind() != ObjectFile::Atom::kAbsoluteSymbol) ) {
-                                                       uint32_t fileOffset = curSection->fFileOffset + atom->getSectionOffset();
-                                                       if ( fileOffset != end ) {
-                                                               //fprintf(stderr, "writing %d pad bytes, needsNops=%d\n", fileOffset-end, needsNops);
-                                                               if ( needsNops ) {
-                                                                       // fill gaps with no-ops
-                                                                       if ( streaming )
-                                                                               writeNoOps(fd, end, fileOffset);
-                                                                       else
-                                                                               copyNoOps(&wholeBuffer[end], &wholeBuffer[fileOffset]);
-                                                               }
-                                                               else if ( streaming ) {
-                                                                       // zero fill gaps
-                                                                       if ( (fileOffset-end) == 4 ) {
-                                                                               uint32_t zero = 0;
-                                                                               ::pwrite(fd, &zero, 4, end);
-                                                                       }
-                                                                       else {
-                                                                               uint8_t zero = 0x00;
-                                                                               for (uint32_t p=end; p < fileOffset; ++p)
-                                                                                       ::pwrite(fd, &zero, 1, p);
-                                                                       }
-                                                               }
-                                                       }
-                                                       uint64_t atomSize = atom->getSize();
-                                                       if ( streaming ) {
-                                                               if ( atomSize > fLargestAtomSize ) 
-                                                                       throwf("ld64 internal error: atom \"%s\"is larger than expected 0x%llX > 0x%X", 
-                                                                                               atom->getDisplayName(), atomSize, fLargestAtomSize);
-                                                       }
-                                                       else {
-                                                               if ( fileOffset > fileBufferSize )
-                                                                       throwf("ld64 internal error: atom \"%s\" has file offset greater thatn expceted 0x%X > 0x%llX", 
-                                                                                               atom->getDisplayName(), fileOffset, fileBufferSize);
-                                                       }
-                                                       uint8_t* buffer = streaming ? atomBuffer : &wholeBuffer[fileOffset];
-                                                       end = fileOffset+atomSize;
-                                                       // copy raw bytes
-                                                       atom->copyRawContent(buffer);
-                                                       // apply any fix-ups
-                                                       try {
-                                                               std::vector<ObjectFile::Reference*>&  references = atom->getReferences();
-                                                               for (std::vector<ObjectFile::Reference*>::iterator it=references.begin(); it != references.end(); it++) {
-                                                                       ObjectFile::Reference* ref = *it;
-                                                                       if ( fOptions.outputKind() == Options::kObjectFile ) {
-                                                                               // doing ld -r
-                                                                               // skip fix-ups for undefined targets
-                                                                               if ( &(ref->getTarget()) != NULL )
-                                                                                       this->fixUpReferenceRelocatable(ref, atom, buffer);
-                                                                       }
-                                                                       else {
-                                                                               // producing final linked image
-                                                                               this->fixUpReferenceFinal(ref, atom, buffer);
-                                                                       }
-                                                               }
-                                                       }
-                                                       catch (const char* msg) {
-                                                               throwf("%s in %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath());
-                                                       }
-                                                       //fprintf(stderr, "writing 0x%08X -> 0x%08X (addr=0x%llX, size=0x%llX), atom %p %s from %s\n", 
-                                                       //      fileOffset, end, atom->getAddress(), atom->getSize(), atom, atom->getDisplayName(), atom->getFile()->getPath());
-                                                       if ( streaming ) {
-                                                               // write out
-                                                               ::pwrite(fd, buffer, atomSize, fileOffset);
-                                                       }
-                                                       else {
-                                                               if ( (fileOffset + atomSize) > size )
-                                                                       size = fileOffset + atomSize;
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               }
-
-               // update content based UUID
-               if ( fOptions.getUUIDMode() == Options::kUUIDContent ) {
-                       uint8_t digest[CC_MD5_DIGEST_LENGTH];
-                       if ( streaming ) {
-                               // if output file file did not fit in memory, re-read file to generate md5 hash
-                               uint32_t kMD5BufferSize = 16*1024;
-                               uint8_t* md5Buffer = (uint8_t*)::malloc(kMD5BufferSize);
-                               if ( md5Buffer != NULL ) {
-                                       CC_MD5_CTX md5State;
-                                       CC_MD5_Init(&md5State);
-                                       ::lseek(fd, 0, SEEK_SET);
-                                       ssize_t len;
-                                       while ( (len = ::read(fd, md5Buffer, kMD5BufferSize)) > 0 ) 
-                                               CC_MD5_Update(&md5State, md5Buffer, len);
-                                       CC_MD5_Final(digest, &md5State);
-                                       ::free(md5Buffer);
-                               }
-                               else {
-                                       // if malloc fails, fall back to random uuid
-                                       ::uuid_generate_random(digest);
-                               }
-                               fUUIDAtom->setContent(digest);
-                               uint32_t uuidOffset = ((SectionInfo*)fUUIDAtom->getSection())->fFileOffset + fUUIDAtom->getSectionOffset();
-                               fUUIDAtom->copyRawContent(atomBuffer);
-                               ::pwrite(fd, atomBuffer, fUUIDAtom->getSize(), uuidOffset);
-                       }
-                       else {
-                               // if output file fit in memory, just genrate an md5 hash in memory
-                       #if 1
-                               // temp hack for building on Tiger
-                               CC_MD5_CTX md5State;
-                               CC_MD5_Init(&md5State);
-                               CC_MD5_Update(&md5State, wholeBuffer, size);
-                               CC_MD5_Final(digest, &md5State);
-                       #else
-                               CC_MD5(wholeBuffer, size, digest);
-                       #endif
-                               fUUIDAtom->setContent(digest);
-                               uint32_t uuidOffset = ((SectionInfo*)fUUIDAtom->getSection())->fFileOffset + fUUIDAtom->getSectionOffset();
-                               fUUIDAtom->copyRawContent(&wholeBuffer[uuidOffset]);
-                       }
-               }
-       }
-       catch (...) {
-               if ( sCleanupFile != NULL ) 
-                       ::unlink(sCleanupFile);
-               throw;
-       }
-       
-       // finish up
-       if ( streaming ) {
-               delete [] atomBuffer;
-               close(fd);
-               // restore default signal handlers
-               sCleanupFile = NULL;
-               ::signal(SIGINT, SIG_DFL);
-               ::signal(SIGBUS, SIG_DFL);
-               ::signal(SIGSEGV, SIG_DFL);
-       }
-       else {
-               // write whole output file in one chunk
-               fd = open(fFilePath, O_CREAT | O_WRONLY | O_TRUNC, permissions);
-               if ( fd == -1 ) 
-                       throwf("can't open output file for writing: %s, errno=%d", fFilePath, errno);
-               ::pwrite(fd, wholeBuffer, size, 0);
-               close(fd);
-               delete [] wholeBuffer;
-       }
-       
-       return end;
-}
-
-template <>
-void Writer<arm>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
-{
-       int64_t         displacement;
-       int64_t         baseAddr;
-       uint32_t        instruction;
-       uint32_t        newInstruction;
-       uint64_t        targetAddr = 0;
-       uint32_t        firstDisp;
-       uint32_t        nextDisp;
-       uint32_t        opcode = 0;
-       int32_t         diff;
-       bool            relocateableExternal = false;
-       bool            is_bl;
-       bool            is_blx;
-       bool            targetIsThumb;
-
-       if ( ref->getTargetBinding() != ObjectFile::Reference::kDontBind ) {
-               targetAddr = ref->getTarget().getAddress() + ref->getTargetOffset();
-               relocateableExternal = (relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal);
-       }
-
-       uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
-       switch ( (arm::ReferenceKinds)(ref->getKind()) ) {
-               case arm::kNoFixUp:
-               case arm::kFollowOn:
-               case arm::kGroupSubordinate:
-                       // do nothing
-                       break;
-               case arm::kPointerWeakImport:
-               case arm::kPointer:
-                       // If this is the lazy pointers section, then set all lazy pointers to
-                       // point to the dyld stub binding helper.
-                       if ( ((SectionInfo*)inAtom->getSection())->fAllLazyPointers 
-                         || ((SectionInfo*)inAtom->getSection())->fAllLazyDylibPointers ) {
-                               switch (ref->getTarget().getDefinitionKind()) {
-                                       case ObjectFile::Atom::kExternalDefinition:
-                                       case ObjectFile::Atom::kExternalWeakDefinition:
-                                               // prebound lazy pointer to another dylib ==> pointer contains zero
-                                               LittleEndian::set32(*fixUp, 0);
-                                               break;
-                                       case ObjectFile::Atom::kTentativeDefinition:
-                                       case ObjectFile::Atom::kRegularDefinition:
-                                       case ObjectFile::Atom::kWeakDefinition:
-                                       case ObjectFile::Atom::kAbsoluteSymbol:
-                                               // prebound lazy pointer to withing this dylib ==> pointer contains address
-                                               if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0) )
-                                                       targetAddr |= 1;
-                                               LittleEndian::set32(*fixUp, targetAddr);
-                                               break;
-                               }
-                       }
-                       else if ( relocateableExternal ) {
-                               if ( fOptions.prebind() ) {
-                                       switch (ref->getTarget().getDefinitionKind()) {
-                                               case ObjectFile::Atom::kExternalDefinition:
-                                               case ObjectFile::Atom::kExternalWeakDefinition:
-                                                       // prebound external relocation ==> pointer contains addend
-                                                       LittleEndian::set32(*fixUp, ref->getTargetOffset());
-                                                       break;
-                                               case ObjectFile::Atom::kTentativeDefinition:
-                                               case ObjectFile::Atom::kRegularDefinition:
-                                               case ObjectFile::Atom::kWeakDefinition:
-                                                       // prebound external relocation to internal atom ==> pointer contains target address + addend
-                                                       if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0) )
-                                                               targetAddr |= 1;
-                                                       LittleEndian::set32(*fixUp, targetAddr);
-                                                       break;
-                                               case ObjectFile::Atom::kAbsoluteSymbol:
-                                                       break;
-                                       }
-                               } 
-                               else if ( !fOptions.makeClassicDyldInfo() 
-                                                               && (ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kWeakDefinition) ) {
-                                       // when using only compressed dyld info, pointer is initially set to point directly to weak definition
-                                       if ( ref->getTarget().isThumb() )
-                                               targetAddr |= 1;
-                                       LittleEndian::set32(*fixUp, targetAddr);
-                               }
-                               else {
-                                       // external relocation ==> pointer contains addend
-                                       LittleEndian::set32(*fixUp, ref->getTargetOffset());
-                               }
-                       }
-                       else {
-                               // pointer contains target address
-                               if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0))
-                                       targetAddr |= 1;
-                               LittleEndian::set32(*fixUp, targetAddr);
-                       }
-                       break;
-               case arm::kPointerDiff:
-                       diff = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
-                       if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0) )
-                               diff |= 1;
-                       LittleEndian::set32(*fixUp, diff);
-                       break;
-               case arm::kReadOnlyPointer:
-                       if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0))
-                               targetAddr |= 1;
-                       switch ( ref->getTarget().getDefinitionKind() ) {
-                               case ObjectFile::Atom::kRegularDefinition:
-                               case ObjectFile::Atom::kWeakDefinition:
-                               case ObjectFile::Atom::kTentativeDefinition:
-                                       // pointer contains target address
-                                       LittleEndian::set32(*fixUp, targetAddr);
-                                       break;
-                               case ObjectFile::Atom::kExternalDefinition:
-                               case ObjectFile::Atom::kExternalWeakDefinition:
-                                       // external relocation ==> pointer contains addend
-                                       LittleEndian::set32(*fixUp, ref->getTargetOffset());
-                                       break;
-                               case ObjectFile::Atom::kAbsoluteSymbol:
-                                       // pointer contains target address
-                                       LittleEndian::set32(*fixUp, targetAddr);
-                                       break;
-                       }
-                       break;
-               case arm::kBranch24WeakImport:
-               case arm::kBranch24:
-                       displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
-                       // check if this is a branch to a branch island that can be skipped
-                       if ( ref->getTarget().getContentType() == ObjectFile::Atom::kBranchIsland ) {
-                               uint64_t finalTargetAddress = ((BranchIslandAtom<arm>*)(&(ref->getTarget())))->getFinalTargetAdress();
-                               int64_t altDisplacment = finalTargetAddress - (inAtom->getAddress() + ref->getFixUpOffset());
-                               if ( (altDisplacment < 33554428LL) && (altDisplacment > (-33554432LL)) ) {
-                                       //fprintf(stderr, "using altDisplacment = %lld\n", altDisplacment);
-                                       // yes, we can skip the branch island
-                                       displacement = altDisplacment;
-                               }
-                       }
-                       // The pc added will be +8 from the pc
-                       displacement -= 8;
-                       //fprintf(stderr, "bl/blx fixup to %s at 0x%08llX, displacement = 0x%08llX\n", ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), displacement);
-                       // max positive displacement is 0x007FFFFF << 2
-                       // max negative displacement is 0xFF800000 << 2
-                       if ( (displacement > 33554428LL) || (displacement < (-33554432LL)) ) {
-                               throwf("b/bl/blx out of range (%lld max is +/-32M) from 0x%08llX %s in %s to 0x%08llX %s in %s",
-                                                       displacement, inAtom->getAddress(), inAtom->getDisplayName(), inAtom->getFile()->getPath(),
-                                                       ref->getTarget().getAddress(), ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
-                       }
-                       instruction = LittleEndian::get32(*fixUp);
-                       // Make sure we are calling arm with bl, thumb with blx
-                       is_bl = ((instruction & 0xFF000000) == 0xEB000000);
-                       is_blx = ((instruction & 0xFE000000) == 0xFA000000);
-                       if ( is_bl && ref->getTarget().isThumb() ) {
-                               uint32_t opcode = 0xFA000000;
-                               uint32_t disp = (uint32_t)(displacement >> 2) & 0x00FFFFFF;
-                               uint32_t h_bit = (uint32_t)(displacement << 23) & 0x01000000;
-                               newInstruction = opcode | h_bit | disp;
-                       } 
-                       else if ( is_blx && !ref->getTarget().isThumb() ) {
-                               uint32_t opcode = 0xEB000000;
-                               uint32_t disp = (uint32_t)(displacement >> 2) & 0x00FFFFFF;
-                               newInstruction = opcode | disp;
-                       } 
-                       else if ( !is_bl && !is_blx && ref->getTarget().isThumb() ) {
-                               throwf("don't know how to convert instruction %x referencing %s to thumb",
-                                        instruction, ref->getTarget().getDisplayName());
-                       } 
-                       else {
-                               newInstruction = (instruction & 0xFF000000) | ((uint32_t)(displacement >> 2) & 0x00FFFFFF);
-                       }
-                       LittleEndian::set32(*fixUp, newInstruction);
-                       break;
-               case arm::kThumbBranch22WeakImport:
-               case arm::kThumbBranch22:
-                       instruction = LittleEndian::get32(*fixUp);
-                       is_bl = ((instruction & 0xD000F800) == 0xD000F000);
-                       is_blx = ((instruction & 0xD000F800) == 0xC000F000);
-                       targetIsThumb = ref->getTarget().isThumb();
-                       
-                       // The pc added will be +4 from the pc
-                       baseAddr = inAtom->getAddress() + ref->getFixUpOffset() + 4;
-                       // If the target is not thumb, we will be generating a blx instruction
-                       // Since blx cannot have the low bit set, set bit[1] of the target to
-                       // bit[1] of the base address, so that the difference is a multiple of
-                       // 4 bytes.
-                       if ( !targetIsThumb ) {
-                         targetAddr &= -3ULL;
-                         targetAddr |= (baseAddr & 2LL);
-                       }
-                       displacement = targetAddr - baseAddr;
-                       
-                       // max positive displacement is 0x003FFFFE
-                       // max negative displacement is 0xFFC00000
-                       if ( (displacement > 4194302LL) || (displacement < (-4194304LL)) ) {
-                               // armv7 supports a larger displacement
-                               if ( fOptions.preferSubArchitecture() && fOptions.subArchitecture() == CPU_SUBTYPE_ARM_V7 ) {
-                                       if ( (displacement > 16777214) || (displacement < (-16777216LL)) ) {
-                                               throwf("thumb bl/blx out of range (%lld max is +/-16M) from %s in %s to %s in %s",
-                                                               displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
-                                                               ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
-                                       }
-                                       else {
-                                               // The instruction is really two instructions:
-                                               // The lower 16 bits are the first instruction, which contains the high
-                                               //   11 bits of the displacement.
-                                               // The upper 16 bits are the second instruction, which contains the low
-                                               //   11 bits of the displacement, as well as differentiating bl and blx.
-                                               uint32_t s = (uint32_t)(displacement >> 24) & 0x1;
-                                               uint32_t i1 = (uint32_t)(displacement >> 23) & 0x1;
-                                               uint32_t i2 = (uint32_t)(displacement >> 22) & 0x1;
-                                               uint32_t imm10 = (uint32_t)(displacement >> 12) & 0x3FF;
-                                               uint32_t imm11 = (uint32_t)(displacement >> 1) & 0x7FF;
-                                               uint32_t j1 = (i1 == s);
-                                               uint32_t j2 = (i2 == s);
-                                               if ( is_bl ) {
-                                                       if ( targetIsThumb )
-                                                               opcode = 0xD000F000; // keep bl
-                                                       else
-                                                               opcode = 0xC000F000; // change to blx
-                                               } 
-                                               else if ( is_blx ) {
-                                                       if ( targetIsThumb )
-                                                               opcode = 0xD000F000; // change to bl
-                                                       else
-                                                               opcode = 0xC000F000; // keep blx
-                                               } 
-                                               else if ( !is_bl && !is_blx && !targetIsThumb ) {
-                                                 throwf("don't know how to convert instruction %x referencing %s to arm",
-                                                                instruction, ref->getTarget().getDisplayName());
-                                               } 
-                                               nextDisp = (j1 << 13) | (j2 << 11) | imm11;
-                                               firstDisp = (s << 10) | imm10;
-                                               newInstruction = opcode | (nextDisp << 16) | firstDisp;
-                                               //warning("s=%d, j1=%d, j2=%d, imm10=0x%0X, imm11=0x%0X, opcode=0x%08X, first=0x%04X, next=0x%04X, new=0x%08X, disp=0x%llX for %s to %s\n",
-                                               //      s, j1, j2, imm10, imm11, opcode, firstDisp, nextDisp, newInstruction, displacement, inAtom->getDisplayName(), ref->getTarget().getDisplayName());
-                                               LittleEndian::set32(*fixUp, newInstruction);
-                                       }
-                               }
-                               else {
-                                       throwf("thumb bl/blx out of range (%lld max is +/-4M) from %s in %s to %s in %s",
-                                                               displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
-                                                               ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
-                               }
-                       }
-                       else {
-                               // The instruction is really two instructions:
-                               // The lower 16 bits are the first instruction, which contains the high
-                               //   11 bits of the displacement.
-                               // The upper 16 bits are the second instruction, which contains the low
-                               //   11 bits of the displacement, as well as differentiating bl and blx.
-                               firstDisp = (uint32_t)(displacement >> 12) & 0x7FF;
-                               nextDisp = (uint32_t)(displacement >> 1) & 0x7FF;
-                               if ( is_bl && !targetIsThumb ) {
-                                       opcode = 0xE800F000;
-                               } 
-                               else if ( is_blx && targetIsThumb ) {
-                                       opcode = 0xF800F000;
-                               } 
-                               else if ( !is_bl && !is_blx && !targetIsThumb ) {
-                                 throwf("don't know how to convert instruction %x referencing %s to arm",
-                                                instruction, ref->getTarget().getDisplayName());
-                               } 
-                               else {
-                                       opcode = instruction & 0xF800F800;
-                               }
-                               newInstruction = opcode | (nextDisp << 16) | firstDisp;
-                               LittleEndian::set32(*fixUp, newInstruction);
-                       }
-                       break;
-               case arm::kDtraceProbeSite:
-                       if ( inAtom->isThumb() ) {
-                               // change 32-bit blx call site to two thumb NOPs
-                               LittleEndian::set32(*fixUp, 0x46C046C0);
-                       }
-                       else {
-                               // change call site to a NOP
-                               LittleEndian::set32(*fixUp, 0xE1A00000);
-                       }
-                       break;
-               case arm::kDtraceIsEnabledSite:
-                       if ( inAtom->isThumb() ) {
-                               // change 32-bit blx call site to 'nop', 'eor r0, r0'
-                               LittleEndian::set32(*fixUp, 0x46C04040);
-                       }
-                       else {
-                               // change call site to 'eor r0, r0, r0'
-                               LittleEndian::set32(*fixUp, 0xE0200000);
-                       }
-                       break;
-               case arm::kDtraceTypeReference:
-               case arm::kDtraceProbe:
-                       // nothing to fix up
-                       break;
-               case arm::kPointerDiff12:
-                       displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
-                       if ( (displacement > 4092LL) || (displacement <-4092LL) ) {
-                               throwf("ldr 12-bit displacement out of range (%lld max +/-4096) in %s", displacement, inAtom->getDisplayName());
-                       }
-                       instruction = LittleEndian::get32(*fixUp);
-                       if ( displacement >= 0 ) {
-                               instruction &= 0xFFFFF000;
-                               instruction |= ((uint32_t)displacement & 0xFFF);
-                       }
-                       else {
-                               instruction &= 0xFF7FF000;
-                               instruction |= ((uint32_t)(-displacement) & 0xFFF);
-                       }
-                       LittleEndian::set32(*fixUp, instruction);
-                       break;
-       }
-}
-
-template <>
-void Writer<arm>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
-{
-       int64_t         displacement;
-       uint32_t        instruction;
-       uint32_t        newInstruction;
-       uint64_t        targetAddr = 0;
-       int64_t         baseAddr;
-       uint32_t        firstDisp;
-       uint32_t        nextDisp;
-       uint32_t        opcode = 0;
-       int32_t         diff;
-       bool            relocateableExternal = false;
-       bool            is_bl;
-       bool            is_blx;
-       bool            targetIsThumb;
-
-       if ( ref->getTargetBinding() != ObjectFile::Reference::kDontBind ) {
-               targetAddr = ref->getTarget().getAddress() + ref->getTargetOffset();
-               relocateableExternal = this->makesExternalRelocatableReference(ref->getTarget());       
-       }
-
-       uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
-       switch ( (arm::ReferenceKinds)(ref->getKind()) ) {
-               case arm::kNoFixUp:
-               case arm::kFollowOn:
-               case arm::kGroupSubordinate:
-                       // do nothing
-                       break;
-               case arm::kPointer:
-               case arm::kReadOnlyPointer:
-               case arm::kPointerWeakImport:
-                       if ( ((SectionInfo*)inAtom->getSection())->fAllNonLazyPointers ) {
-                               // indirect symbol table has INDIRECT_SYMBOL_LOCAL, so we must put address in content
-                               if ( this->indirectSymbolInRelocatableIsLocal(ref) ) 
-                                       LittleEndian::set32(*fixUp, targetAddr);
-                               else
-                                       LittleEndian::set32(*fixUp, 0);
-                       }
-                       else if ( relocateableExternal ) {
-                               if ( fOptions.prebind() ) {
-                                       switch (ref->getTarget().getDefinitionKind()) {
-                                               case ObjectFile::Atom::kExternalDefinition:
-                                               case ObjectFile::Atom::kExternalWeakDefinition:
-                                                       // prebound external relocation ==> pointer contains addend
-                                                       LittleEndian::set32(*fixUp, ref->getTargetOffset());
-                                                       break;
-                                               case ObjectFile::Atom::kTentativeDefinition:
-                                               case ObjectFile::Atom::kRegularDefinition:
-                                               case ObjectFile::Atom::kWeakDefinition:
-                                                       // prebound external relocation to internal atom ==> pointer contains target address + addend
-                                                       LittleEndian::set32(*fixUp, targetAddr);
-                                                       break;
-                                               case ObjectFile::Atom::kAbsoluteSymbol:
-                                                       break;
-                                       }
-                               }
-                       }
-                       else {
-                               // internal relocation =>  pointer contains target address
-                               if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0) )
-                                               targetAddr |= 1;
-                               LittleEndian::set32(*fixUp, targetAddr);
-                       }
-                       break;
-               case arm::kPointerDiff:
-                       diff = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
-                       if ( ref->getTarget().isThumb() && (ref->getTargetOffset() == 0) )
-                               diff |= 1;
-                       LittleEndian::set32(*fixUp, diff);
-                       break;
-               case arm::kDtraceProbeSite:
-               case arm::kDtraceIsEnabledSite:
-               case arm::kBranch24WeakImport:
-               case arm::kBranch24:
-                       displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
-                       // The pc added will be +8 from the pc
-                       displacement -= 8;
-                       // fprintf(stderr, "b/bl/blx fixup to %s at 0x%08llX, displacement = 0x%08llX\n", ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), displacement);
-                       if ( relocateableExternal )  {
-                               // doing "ld -r" to an external symbol
-                               // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
-                               displacement -= ref->getTarget().getAddress();
-                       }
-                       else {
-                               // max positive displacement is 0x007FFFFF << 2
-                               // max negative displacement is 0xFF800000 << 2
-                               if ( (displacement > 33554428LL) || (displacement < (-33554432LL)) ) {
-                                       throwf("arm b/bl/blx out of range (%lld max is +/-32M) from %s in %s to %s in %s",
-                                                       displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
-                                                       ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
-                               }
-                       }
-                       instruction = LittleEndian::get32(*fixUp);
-                       // Make sure we are calling arm with bl, thumb with blx
-                       is_bl = ((instruction & 0xFF000000) == 0xEB000000);
-                       is_blx = ((instruction & 0xFE000000) == 0xFA000000);
-                       if ( is_bl && ref->getTarget().isThumb() ) {
-                               uint32_t opcode = 0xFA000000;
-                               uint32_t disp = (uint32_t)(displacement >> 2) & 0x00FFFFFF;
-                               uint32_t h_bit = (uint32_t)(displacement << 23) & 0x01000000;
-                               newInstruction = opcode | h_bit | disp;
-                       }
-                       else if ( is_blx && !ref->getTarget().isThumb() ) {
-                               uint32_t opcode = 0xEB000000;
-                               uint32_t disp = (uint32_t)(displacement >> 2) & 0x00FFFFFF;
-                               newInstruction = opcode | disp;
-                       } 
-                       else if ( !is_bl && !is_blx && ref->getTarget().isThumb() ) {
-                               throwf("don't know how to convert instruction %x referencing %s to thumb",
-                                        instruction, ref->getTarget().getDisplayName());
-                       } 
-                       else {
-                               newInstruction = (instruction & 0xFF000000) | ((uint32_t)(displacement >> 2) & 0x00FFFFFF);
-                       }
-                       LittleEndian::set32(*fixUp, newInstruction);
-                       break;
-               case arm::kThumbBranch22WeakImport:
-               case arm::kThumbBranch22:
-                       instruction = LittleEndian::get32(*fixUp);
-                       is_bl = ((instruction & 0xF8000000) == 0xF8000000);
-                       is_blx = ((instruction & 0xF8000000) == 0xE8000000);
-                       targetIsThumb = ref->getTarget().isThumb();
-                       
-                       // The pc added will be +4 from the pc
-                       baseAddr = inAtom->getAddress() + ref->getFixUpOffset() + 4;
-                       // If the target is not thumb, we will be generating a blx instruction
-                       // Since blx cannot have the low bit set, set bit[1] of the target to
-                       // bit[1] of the base address, so that the difference is a multiple of
-                       // 4 bytes.
-                       if (!targetIsThumb) {
-                               targetAddr &= -3ULL;
-                               targetAddr |= (baseAddr & 2LL);
-                       }
-                       displacement = targetAddr - baseAddr;
-                       
-                       //fprintf(stderr, "thumb %s fixup to %s at 0x%08llX, baseAddr = 0x%08llX, displacement = 0x%08llX, %d\n", is_blx ? "blx" : "bl",  ref->getTarget().getDisplayName(), targetAddr, baseAddr, displacement, targetIsThumb);
-                       if ( relocateableExternal )  {
-                               // doing "ld -r" to an external symbol
-                               // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
-                               displacement -= ref->getTarget().getAddress();
-                       }
-                       
-                       if ( (displacement > 4194302LL) || (displacement < (-4194304LL)) ) {
-                               // armv7 supports a larger displacement
-                               if ( fOptions.preferSubArchitecture() && fOptions.subArchitecture() == CPU_SUBTYPE_ARM_V7 ) {
-                                       if ( (displacement > 16777214) || (displacement < (-16777216LL)) ) {
-                                               throwf("thumb bl/blx out of range (%lld max is +/-16M) from %s in %s to %s in %s",
-                                                               displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
-                                                               ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
-                                       }
-                                       else {
-                                               // The instruction is really two instructions:
-                                               // The lower 16 bits are the first instruction, which contains the high
-                                               //   11 bits of the displacement.
-                                               // The upper 16 bits are the second instruction, which contains the low
-                                               //   11 bits of the displacement, as well as differentiating bl and blx.
-                                               uint32_t s = (uint32_t)(displacement >> 24) & 0x1;
-                                               uint32_t i1 = (uint32_t)(displacement >> 23) & 0x1;
-                                               uint32_t i2 = (uint32_t)(displacement >> 22) & 0x1;
-                                               uint32_t imm10 = (uint32_t)(displacement >> 12) & 0x3FF;
-                                               uint32_t imm11 = (uint32_t)(displacement >> 1) & 0x7FF;
-                                               uint32_t j1 = (i1 == s);
-                                               uint32_t j2 = (i2 == s);
-                                               if ( is_bl ) {
-                                                       if ( targetIsThumb )
-                                                               opcode = 0xD000F000; // keep bl
-                                                       else
-                                                               opcode = 0xC000F000; // change to blx
-                                               } 
-                                               else if ( is_blx ) {
-                                                       if ( targetIsThumb )
-                                                               opcode = 0xD000F000; // change to bl
-                                                       else
-                                                               opcode = 0xC000F000; // keep blx
-                                               } 
-                                               else if ( !is_bl && !is_blx && !targetIsThumb ) {
-                                                 throwf("don't know how to convert instruction %x referencing %s to arm",
-                                                                instruction, ref->getTarget().getDisplayName());
-                                               } 
-                                               nextDisp = (j1 << 13) | (j2 << 11) | imm11;
-                                               firstDisp = (s << 10) | imm10;
-                                               newInstruction = opcode | (nextDisp << 16) | firstDisp;
-                                               //warning("s=%d, j1=%d, j2=%d, imm10=0x%0X, imm11=0x%0X, opcode=0x%08X, first=0x%04X, next=0x%04X, new=0x%08X, disp=0x%llX for %s to %s\n",
-                                               //      s, j1, j2, imm10, imm11, opcode, firstDisp, nextDisp, newInstruction, displacement, inAtom->getDisplayName(), ref->getTarget().getDisplayName());
-                                               LittleEndian::set32(*fixUp, newInstruction);
-                                               break;
-                                       }
-                               }
-                               else {
-                                       throwf("thumb bl/blx out of range (%lld max is +/-4M) from %s in %s to %s in %s",
-                                                               displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
-                                                               ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
-                               }
-                       }
-                       // The instruction is really two instructions:
-                       // The lower 16 bits are the first instruction, which contains the first
-                       //   11 bits of the displacement.
-                       // The upper 16 bits are the second instruction, which contains the next
-                       //   11 bits of the displacement, as well as differentiating bl and blx.
-                       firstDisp = (uint32_t)(displacement >> 12) & 0x7FF;
-                       nextDisp = (uint32_t)(displacement >> 1) & 0x7FF;
-                       if ( is_bl && !targetIsThumb ) {
-                               opcode = 0xE800F000;
-                       } 
-                       else if ( is_blx && targetIsThumb ) {
-                               opcode = 0xF800F000;
-                       } 
-                       else if ( !is_bl && !is_blx && !targetIsThumb ) {
-                               throwf("don't know how to convert instruction %x referencing %s to arm",
-                                        instruction, ref->getTarget().getDisplayName());
-                       } 
-                       else {
-                               opcode = instruction & 0xF800F800;
-                       }
-                       newInstruction = opcode | (nextDisp << 16) | firstDisp;
-                       LittleEndian::set32(*fixUp, newInstruction);
-                       break;
-               case arm::kDtraceProbe:
-               case arm::kDtraceTypeReference:
-                       // nothing to fix up
-                       break;
-               case arm::kPointerDiff12:
-                       throw "internal error.  no reloc for 12-bit pointer diffs";
-       }
-}
-
-template <>
-void Writer<x86>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
-{
-       uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
-       uint8_t*  dtraceProbeSite;
-       const int64_t kTwoGigLimit = 0x7FFFFFFF;
-       const int64_t kSixteenMegLimit = 0x00FFFFFF;
-       const int64_t kSixtyFourKiloLimit = 0x7FFF;
-       const int64_t kOneTwentyEightLimit = 0x7F;
-       int64_t displacement;
-       uint32_t temp;
-       x86::ReferenceKinds kind = (x86::ReferenceKinds)(ref->getKind());
-       switch ( kind ) {
-               case x86::kNoFixUp:
-               case x86::kFollowOn:
-               case x86::kGroupSubordinate:
-                       // do nothing
-                       break;
-               case x86::kPointerWeakImport:
-               case x86::kPointer:
-                       {
-                               if ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal ) {
-                                       if ( fOptions.prebind() ) {
-                                               switch (ref->getTarget().getDefinitionKind()) {
-                                                       case ObjectFile::Atom::kExternalDefinition:
-                                                       case ObjectFile::Atom::kExternalWeakDefinition:
-                                                               // prebound external relocation ==> pointer contains addend
-                                                               LittleEndian::set32(*fixUp, ref->getTargetOffset());
-                                                               break;
-                                                       case ObjectFile::Atom::kTentativeDefinition:
-                                                       case ObjectFile::Atom::kRegularDefinition:
-                                                       case ObjectFile::Atom::kWeakDefinition:
-                                                               // prebound external relocation to internal atom ==> pointer contains target address + addend
-                                                               LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
-                                                               break;
-                                                       case ObjectFile::Atom::kAbsoluteSymbol:
-                                                               break;
-                                               }
-                                       } 
-                                       else if ( !fOptions.makeClassicDyldInfo() 
-                                                                       && (ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kWeakDefinition) ) {
-                                               // when using only compressed dyld info, pointer is initially set to point directly to weak definition
-                                               LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
-                                       }
-                                       else {
-                                               // external relocation ==> pointer contains addend
-                                               LittleEndian::set32(*fixUp, ref->getTargetOffset());
-                                       }
-                               }
-                               else {
-                                       // pointer contains target address
-                                       //printf("Atom::fixUpReferenceFinal() target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
-                                       LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
-                               }
-                       }
-                       break;
-               case x86::kPointerDiff:
-                       displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
-                       LittleEndian::set32(*fixUp, (uint32_t)displacement);
-                       break;
-               case x86::kPointerDiff16:
-                       displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
-                       if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) ) 
-                               throwf("16-bit pointer diff out of range in %s", inAtom->getDisplayName());
-                       LittleEndian::set16(*((uint16_t*)fixUp), (uint16_t)displacement);
-                       break;
-               case x86::kPointerDiff24:
-                       displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
-                       if ( (displacement > kSixteenMegLimit) || (displacement < 0) ) 
-                               throwf("24-bit pointer diff out of range in %s", inAtom->getDisplayName());
-                       temp = LittleEndian::get32(*fixUp);
-                       temp &= 0xFF000000;
-                       temp |= (displacement & 0x00FFFFFF);
-                       LittleEndian::set32(*fixUp, temp);
-                       break;
-               case x86::kSectionOffset24:
-                       displacement = ref->getTarget().getSectionOffset();
-                       if ( (displacement > kSixteenMegLimit) || (displacement < 0) ) 
-                               throwf("24-bit pointer diff out of range in %s", inAtom->getDisplayName());
-                       temp = LittleEndian::get32(*fixUp);
-                       temp &= 0xFF000000;
-                       temp |= (displacement & 0x00FFFFFF);
-                       LittleEndian::set32(*fixUp, temp);
-                       break;
-               case x86::kDtraceProbeSite:
-                       // change call site to a NOP
-                       dtraceProbeSite = (uint8_t*)fixUp;
-                       dtraceProbeSite[-1] = 0x90;     // 1-byte nop
-                       dtraceProbeSite[0] = 0x0F;      // 4-byte nop 
-                       dtraceProbeSite[1] = 0x1F;
-                       dtraceProbeSite[2] = 0x40;
-                       dtraceProbeSite[3] = 0x00;
-                       break;
-               case x86::kDtraceIsEnabledSite:
-                       // change call site to a clear eax
-                       dtraceProbeSite = (uint8_t*)fixUp;
-                       dtraceProbeSite[-1] = 0x33;             // xorl eax,eax
-                       dtraceProbeSite[0] = 0xC0;
-                       dtraceProbeSite[1] = 0x90;              // 1-byte nop
-                       dtraceProbeSite[2] = 0x90;              // 1-byte nop
-                       dtraceProbeSite[3] = 0x90;              // 1-byte nop
-                       break;
-               case x86::kPCRel32WeakImport:
-               case x86::kPCRel32:
-               case x86::kPCRel16:
-               case x86::kPCRel8:
-                       displacement = 0;
-                       switch ( ref->getTarget().getDefinitionKind() ) {
-                               case ObjectFile::Atom::kRegularDefinition:
-                               case ObjectFile::Atom::kWeakDefinition:
-                                       displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
-                                       break;
-                               case ObjectFile::Atom::kExternalDefinition:
-                               case ObjectFile::Atom::kExternalWeakDefinition:
-                                       throw "codegen problem, can't use rel32 to external symbol";
-                               case ObjectFile::Atom::kTentativeDefinition:
-                                       displacement = 0;
-                                       break;
-                               case ObjectFile::Atom::kAbsoluteSymbol:
-                                       displacement = (ref->getTarget().getSectionOffset() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
-                                       break;
-                       }
-                       if ( kind == x86::kPCRel8 ) {
-                               displacement += 3;
-                               if ( (displacement > kOneTwentyEightLimit) || (displacement < -(kOneTwentyEightLimit)) ) {
-                                       //fprintf(stderr, "call out of range from %s in %s to %s in %s\n", this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath());
-                                       throwf("rel8 out of range in %s", inAtom->getDisplayName());
-                               }
-                               *(int8_t*)fixUp = (int8_t)displacement;
-                       }
-                       else if ( kind == x86::kPCRel16 ) {
-                               displacement += 2;
-                               if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) ) {
-                                       //fprintf(stderr, "call out of range from %s in %s to %s in %s\n", this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath());
-                                       throwf("rel16 out of range in %s", inAtom->getDisplayName());
-                               }
-                               LittleEndian::set16(*((uint16_t*)fixUp), (uint16_t)displacement);
-                       }
-                       else {
-                               if ( (displacement > kTwoGigLimit) || (displacement < (-kTwoGigLimit)) ) {
-                                       //fprintf(stderr, "call out of range from %s in %s to %s in %s\n", this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath());
-                                       throwf("rel32 out of range in %s", inAtom->getDisplayName());
-                               }
-                               LittleEndian::set32(*fixUp, (int32_t)displacement);
-                       }
-                       break;
-               case x86::kAbsolute32:
-                       switch ( ref->getTarget().getDefinitionKind() ) {
-                               case ObjectFile::Atom::kRegularDefinition:
-                               case ObjectFile::Atom::kWeakDefinition:
-                               case ObjectFile::Atom::kTentativeDefinition:
-                                       // pointer contains target address
-                                       LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
-                                       break;
-                               case ObjectFile::Atom::kExternalDefinition:
-                               case ObjectFile::Atom::kExternalWeakDefinition:
-                                       // external relocation ==> pointer contains addend
-                                       LittleEndian::set32(*fixUp, ref->getTargetOffset());
-                                       break;
-                               case ObjectFile::Atom::kAbsoluteSymbol:
-                                       // pointer contains target address
-                                       LittleEndian::set32(*fixUp, ref->getTarget().getSectionOffset() + ref->getTargetOffset());
-                                       break;
-                       }
-                       break;
-               case x86::kImageOffset32:
-                       // offset of target atom from mach_header
-                       displacement = ref->getTarget().getAddress() + ref->getTargetOffset() - fMachHeaderAtom->getAddress();
-                       LittleEndian::set32(*fixUp, (int32_t)displacement);
-                       break;
-               case x86::kDtraceTypeReference:
-               case x86::kDtraceProbe:
-                       // nothing to fix up
-                       break;
-       }
-}
-
-
-
-template <>
-void Writer<x86>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
-{
-       const int64_t kTwoGigLimit = 0x7FFFFFFF;
-       const int64_t kSixtyFourKiloLimit = 0x7FFF;
-       const int64_t kOneTwentyEightLimit = 0x7F;
-       uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
-       bool isExtern = this->makesExternalRelocatableReference(ref->getTarget());      
-       int64_t displacement;
-       x86::ReferenceKinds kind = (x86::ReferenceKinds)(ref->getKind());
-       switch ( kind ) {
-               case x86::kNoFixUp:
-               case x86::kFollowOn:
-               case x86::kGroupSubordinate:
-                       // do nothing
-                       break;
-               case x86::kPointer:
-               case x86::kPointerWeakImport:
-               case x86::kAbsolute32:
-                       {
-                               if ( ((SectionInfo*)inAtom->getSection())->fAllNonLazyPointers ) {
-                                       // if INDIRECT_SYMBOL_LOCAL the content is pointer, else it is zero
-                                       if ( this->indirectSymbolInRelocatableIsLocal(ref) ) 
-                                               LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
-                                       else
-                                               LittleEndian::set32(*fixUp, 0);
-                               } 
-                               else if ( isExtern ) {
-                                       // external relocation ==> pointer contains addend
-                                       LittleEndian::set32(*fixUp, ref->getTargetOffset());
-                               }
-                               else if ( ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition ) {
-                                       // internal relocation => pointer contains target address
-                                       LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
-                               }
-                               else {
-                                       // internal relocation to tentative ==> pointer contains addend
-                                       LittleEndian::set32(*fixUp, ref->getTargetOffset());
-                               }
-                       }
-                       break;
-               case x86::kPointerDiff:
-                               displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
-                               LittleEndian::set32(*fixUp, (uint32_t)displacement);
-                       break;
-               case x86::kPointerDiff16:
-                               displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
-                               if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) ) 
-                                       throwf("16-bit pointer diff out of range in %s", inAtom->getDisplayName());
-                               LittleEndian::set16(*((uint16_t*)fixUp), (uint16_t)displacement);
-                       break;
-               case x86::kPCRel8:
-               case x86::kPCRel16:
-               case x86::kPCRel32:
-               case x86::kPCRel32WeakImport:
-               case x86::kDtraceProbeSite:
-               case x86::kDtraceIsEnabledSite:
-                       {
-                               if ( isExtern )
-                                       displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
-                               else
-                                       displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
-                               if ( kind == x86::kPCRel8 ) {
-                                       displacement += 3;
-                                       if ( (displacement > kOneTwentyEightLimit) || (displacement < -(kOneTwentyEightLimit)) ) {
-                                               //fprintf(stderr, "call out of range from %s in %s to %s in %s\n", this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath());
-                                               throwf("rel8 out of range (%lld)in %s", displacement, inAtom->getDisplayName());
-                                       }
-                                       int8_t byte = (int8_t)displacement;
-                                       *((int8_t*)fixUp) = byte;
-                               }
-                               else if ( kind == x86::kPCRel16 ) {
-                                       displacement += 2;
-                                       if ( (displacement > kSixtyFourKiloLimit) || (displacement < -(kSixtyFourKiloLimit)) ) {
-                                               //fprintf(stderr, "call out of range from %s in %s to %s in %s\n", this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath());
-                                               throwf("rel16 out of range in %s", inAtom->getDisplayName());
-                                       }
-                                       int16_t word = (int16_t)displacement;
-                                       LittleEndian::set16(*((uint16_t*)fixUp), word);
-                               }
-                               else {
-                                       if ( (displacement > kTwoGigLimit) || (displacement < (-kTwoGigLimit)) ) {
-                                               //fprintf(stderr, "call out of range, displacement=ox%llX, from %s in %s to %s in %s\n", displacement, 
-                                               //      inAtom->getDisplayName(), inAtom->getFile()->getPath(), ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
-                                               throwf("rel32 out of range in %s", inAtom->getDisplayName());
-                                       }
-                                       LittleEndian::set32(*fixUp, (int32_t)displacement);
-                               }
-                       }
-                       break;
-               case x86::kPointerDiff24:
-                       throw "internal linker error, kPointerDiff24 can't be encoded into object files";
-               case x86::kImageOffset32:
-                       throw "internal linker error, kImageOffset32 can't be encoded into object files";
-               case x86::kSectionOffset24:
-                       throw "internal linker error, kSectionOffset24 can't be encoded into object files";
-               case x86::kDtraceProbe:
-               case x86::kDtraceTypeReference:
-                       // nothing to fix up
-                       break;
-       }
-}
-
-template <>
-void Writer<x86_64>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
-{
-       const int64_t twoGigLimit               = 0x7FFFFFFF;
-       const int64_t kSixteenMegLimit  = 0x00FFFFFF;
-       uint64_t* fixUp = (uint64_t*)&buffer[ref->getFixUpOffset()];
-       uint8_t*  dtraceProbeSite;
-       int64_t displacement = 0;
-       uint32_t temp;
-       switch ( (x86_64::ReferenceKinds)(ref->getKind()) ) {
-               case x86_64::kNoFixUp:
-               case x86_64::kGOTNoFixUp:
-               case x86_64::kFollowOn:
-               case x86_64::kGroupSubordinate:
-                       // do nothing
-                       break;
-               case x86_64::kPointerWeakImport:
-               case x86_64::kPointer:
-                       {
-                               if ( &ref->getTarget() != NULL ) {
-                                       //fprintf(stderr, "fixUpReferenceFinal: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
-                                       if ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal) {
-                                               if ( !fOptions.makeClassicDyldInfo() 
-                                                                       && (ref->getTarget().getDefinitionKind() == ObjectFile::Atom::kWeakDefinition) ) {
-                                                       // when using only compressed dyld info, pointer is initially set to point directly to weak definition
-                                                       LittleEndian::set64(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
-                                               }
-                                               else {
-                                                       // external relocation ==> pointer contains addend
-                                                       LittleEndian::set64(*fixUp, ref->getTargetOffset());
-                                               }
-                                       }
-                                       else {
-                                               // internal relocation
-                                               // pointer contains target address
-                                               //printf("Atom::fixUpReferenceFinal) target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
-                                               LittleEndian::set64(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
-                                       }
-                               }
-                       }
-                       break;
-               case x86_64::kPointer32:
-                       {
-                               //fprintf(stderr, "fixUpReferenceFinal: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
-                               if ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal ) {
-                                       // external relocation
-                                       throwf("32-bit pointer to dylib or weak symbol %s not supported for x86_64",ref->getTarget().getDisplayName());
-                               }
-                               else {
-                                       // internal relocation
-                                       // pointer contains target address
-                                       //printf("Atom::fixUpReferenceFinal) target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
-                                       displacement = ref->getTarget().getAddress() + ref->getTargetOffset();
-                                       switch ( fOptions.outputKind() ) {
-                                               case Options::kObjectFile:
-                                               case Options::kPreload:
-                                               case Options::kDyld:
-                                               case Options::kDynamicLibrary:
-                                               case Options::kDynamicBundle:
-                                               case Options::kKextBundle:
-                                                       throwf("32-bit pointer to symbol %s not supported for x86_64",ref->getTarget().getDisplayName());
-                                               case Options::kDynamicExecutable:
-                                                       // <rdar://problem/5855588> allow x86_64 main executables to use 32-bit pointers if program loads in load 2GB
-                                                       if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) )
-                                                               throw "32-bit pointer out of range";
-                                                       break;
-                                               case Options::kStaticExecutable:
-                                                       // <rdar://problem/5855588> allow x86_64 mach_kernel to truncate pointers
-                                                       break;
-                                       }
-                                       LittleEndian::set32(*((uint32_t*)fixUp), (uint32_t)displacement);
-                               }
-                       }
-                       break;
-               case x86_64::kPointerDiff32:
-                       displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
-                       if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) )
-                               throw "32-bit pointer difference out of range";
-                       LittleEndian::set32(*((uint32_t*)fixUp), (uint32_t)displacement);
-                       break;
-               case x86_64::kPointerDiff:
-                       LittleEndian::set64(*fixUp,
-                               (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
-                       break;
-               case x86_64::kPointerDiff24:
-                       displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
-                       if ( (displacement > kSixteenMegLimit) || (displacement < 0) ) 
-                               throwf("24-bit pointer diff out of range in %s", inAtom->getDisplayName());
-                       temp = LittleEndian::get32(*((uint32_t*)fixUp));
-                       temp &= 0xFF000000;
-                       temp |= (displacement & 0x00FFFFFF);
-                       LittleEndian::set32(*((uint32_t*)fixUp), temp);
-                       break;
-               case x86_64::kSectionOffset24:
-                       displacement = ref->getTarget().getSectionOffset();
-                       if ( (displacement > kSixteenMegLimit) || (displacement < 0) ) 
-                               throwf("24-bit pointer diff out of range in %s", inAtom->getDisplayName());
-                       temp = LittleEndian::get32(*((uint32_t*)fixUp));
-                       temp &= 0xFF000000;
-                       temp |= (displacement & 0x00FFFFFF);
-                       LittleEndian::set32(*((uint32_t*)fixUp), temp);
-                       break;
-               case x86_64::kPCRel32GOTLoad:
-               case x86_64::kPCRel32GOTLoadWeakImport:
-                       // if GOT entry was optimized away, change movq instruction to a leaq
-                       if ( std::find(fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end(), &(ref->getTarget())) == fAllSynthesizedNonLazyPointers.end() ) {
-                               //fprintf(stderr, "GOT for %s optimized away\n", ref->getTarget().getDisplayName());
-                               uint8_t* opcodes = (uint8_t*)fixUp;
-                               if ( opcodes[-2] != 0x8B )
-                                       throw "GOT load reloc does not point to a movq instruction";
-                               opcodes[-2] = 0x8D;
-                       }
-                       // fall into general rel32 case
-               case x86_64::kBranchPCRel32WeakImport:
-               case x86_64::kBranchPCRel32:
-               case x86_64::kBranchPCRel8:
-               case x86_64::kPCRel32:
-               case x86_64::kPCRel32_1:
-               case x86_64::kPCRel32_2:
-               case x86_64::kPCRel32_4:
-               case x86_64::kPCRel32GOT:
-               case x86_64::kPCRel32GOTWeakImport:
-                       switch ( ref->getTarget().getDefinitionKind() ) {
-                               case ObjectFile::Atom::kRegularDefinition:
-                               case ObjectFile::Atom::kWeakDefinition:
-                               case ObjectFile::Atom::kTentativeDefinition:
-                                       displacement = (ref->getTarget().getAddress() + (int32_t)ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
-                                       break;
-                               case ObjectFile::Atom::kAbsoluteSymbol:
-                                       displacement = (ref->getTarget().getSectionOffset() + (int32_t)ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
-                                       break;
-                               case ObjectFile::Atom::kExternalDefinition:
-                               case ObjectFile::Atom::kExternalWeakDefinition:
-                                       if ( fOptions.outputKind() == Options::kKextBundle )
-                                               displacement = 0;
-                                       else
-                                               throwf("codegen problem, can't use rel32 to external symbol %s", ref->getTarget().getDisplayName());
-                                       break;
-                       }
-                       switch ( ref->getKind() ) {
-                               case x86_64::kPCRel32_1:
-                                       displacement -= 1;
-                                       break;
-                               case x86_64::kPCRel32_2:
-                                       displacement -= 2;
-                                       break;
-                               case x86_64::kPCRel32_4:
-                                       displacement -= 4;
-                                       break;
-                               case x86_64::kBranchPCRel8:
-                                       displacement += 3;
-                                       break;
-                       }
-                       if ( ref->getKind() == x86_64::kBranchPCRel8 ) {
-                               if ( (displacement > 127) || (displacement < (-128)) ) {
-                                       fprintf(stderr, "branch out of range from %s (%llX) in %s to %s (%llX) in %s\n", 
-                                               inAtom->getDisplayName(), inAtom->getAddress(), inAtom->getFile()->getPath(), ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), ref->getTarget().getFile()->getPath());
-                                       throw "rel8 out of range";
-                               }
-                               *((int8_t*)fixUp) = (int8_t)displacement;
-                       }
-                       else {
-                               if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) {
-                                       fprintf(stderr, "reference out of range from %s (%llX) in %s to %s (%llX) in %s\n", 
-                                               inAtom->getDisplayName(), inAtom->getAddress(), inAtom->getFile()->getPath(), ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), ref->getTarget().getFile()->getPath());
-                                       throw "rel32 out of range";
-                               }
-                               LittleEndian::set32(*((uint32_t*)fixUp), (int32_t)displacement);
-                       }
-                       break;
-               case x86_64::kImageOffset32:
-                       // offset of target atom from mach_header
-                       displacement = ref->getTarget().getAddress() + ref->getTargetOffset() - fMachHeaderAtom->getAddress();
-                       LittleEndian::set32(*((uint32_t*)fixUp), (int32_t)displacement);
-                       break;
-               case x86_64::kDtraceProbeSite:
-                       // change call site to a NOP
-                       dtraceProbeSite = (uint8_t*)fixUp;
-                       dtraceProbeSite[-1] = 0x90;     // 1-byte nop
-                       dtraceProbeSite[0] = 0x0F;      // 4-byte nop 
-                       dtraceProbeSite[1] = 0x1F;
-                       dtraceProbeSite[2] = 0x40;
-                       dtraceProbeSite[3] = 0x00;
-                       break;
-               case x86_64::kDtraceIsEnabledSite:
-                       // change call site to a clear eax
-                       dtraceProbeSite = (uint8_t*)fixUp;
-                       dtraceProbeSite[-1] = 0x48;             // xorq eax,eax
-                       dtraceProbeSite[0] = 0x33;
-                       dtraceProbeSite[1] = 0xC0;              
-                       dtraceProbeSite[2] = 0x90;              // 1-byte nop
-                       dtraceProbeSite[3] = 0x90;              // 1-byte nop
-                       break;
-               case x86_64::kDtraceTypeReference:
-               case x86_64::kDtraceProbe:
-                       // nothing to fix up
-                       break;
-       }
-}
-
-template <>
-void Writer<x86_64>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
-{
-       const int64_t twoGigLimit                 = 0x7FFFFFFF;
-       bool external = this->makesExternalRelocatableReference(ref->getTarget());
-       uint64_t* fixUp = (uint64_t*)&buffer[ref->getFixUpOffset()];
-       int64_t displacement = 0;
-       int32_t temp32;
-       switch ( (x86_64::ReferenceKinds)(ref->getKind()) ) {
-               case x86_64::kNoFixUp:
-               case x86_64::kGOTNoFixUp:
-               case x86_64::kFollowOn:
-               case x86_64::kGroupSubordinate:
-                       // do nothing
-                       break;
-               case x86_64::kPointer:
-               case x86_64::kPointerWeakImport:
-                       {
-                               if ( external ) {
-                                       // external relocation ==> pointer contains addend
-                                       LittleEndian::set64(*fixUp, ref->getTargetOffset());
-                               }
-                               else {
-                                       // internal relocation ==> pointer contains target address
-                                       LittleEndian::set64(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
-                               }
-                       }
-                       break;
-               case x86_64::kPointer32:
-                       {
-                               if ( external ) {
-                                       // external relocation ==> pointer contains addend
-                                       LittleEndian::set32(*((uint32_t*)fixUp), ref->getTargetOffset());
-                               }
-                               else {
-                                       // internal relocation ==> pointer contains target address
-                                       LittleEndian::set32(*((uint32_t*)fixUp), ref->getTarget().getAddress() + ref->getTargetOffset());
-                               }
-                       }
-                       break;
-               case x86_64::kPointerDiff32:
-                               displacement = ref->getTargetOffset() - ref->getFromTargetOffset();
-                               if ( ref->getTarget().getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn )
-                                       displacement += ref->getTarget().getAddress();
-                               if ( ref->getFromTarget().getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn ) 
-                                       displacement -= ref->getFromTarget().getAddress();
-                               LittleEndian::set32(*((uint32_t*)fixUp), displacement);
-                       break;
-               case x86_64::kPointerDiff:
-                               displacement = ref->getTargetOffset() - ref->getFromTargetOffset();
-                               if ( ref->getTarget().getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn )
-                                       displacement += ref->getTarget().getAddress();
-                               if ( ref->getFromTarget().getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn ) 
-                                       displacement -= ref->getFromTarget().getAddress();
-                               LittleEndian::set64(*fixUp, displacement);
-                       break;
-               case x86_64::kBranchPCRel32:
-               case x86_64::kBranchPCRel32WeakImport:
-               case x86_64::kDtraceProbeSite:
-               case x86_64::kDtraceIsEnabledSite:
-               case x86_64::kPCRel32:
-               case x86_64::kPCRel32_1:
-               case x86_64::kPCRel32_2:
-               case x86_64::kPCRel32_4:
-                       // turn unsigned 64-bit target offset in signed 32-bit offset, since that is what source originally had
-                       temp32 = ref->getTargetOffset();
-                       if ( external ) {
-                               // extern relocation contains addend
-                               displacement = temp32;
-                       }
-                       else {
-                               // internal relocations contain delta to target address
-                               displacement = (ref->getTarget().getAddress() + temp32) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
-                       }
-                       switch ( ref->getKind() ) {
-                               case x86_64::kPCRel32_1:
-                                       displacement -= 1;
-                                       break;
-                               case x86_64::kPCRel32_2:
-                                       displacement -= 2;
-                                       break;
-                               case x86_64::kPCRel32_4:
-                                       displacement -= 4;
-                                       break;
-                       }
-                       if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) {
-                               //fprintf(stderr, "call out of range from %s in %s to %s in %s\n", this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath());
-                               throw "rel32 out of range";
-                       }
-                       LittleEndian::set32(*((uint32_t*)fixUp), (int32_t)displacement);
-                       break;
-               case x86_64::kBranchPCRel8:
-                       // turn unsigned 64-bit target offset in signed 32-bit offset, since that is what source originally had
-                       temp32 = ref->getTargetOffset();
-                       if ( external ) {
-                               // extern relocation contains addend
-                               displacement = temp32;
-                       }
-                       else {
-                               // internal relocations contain delta to target address
-                               displacement = (ref->getTarget().getAddress() + temp32) - (inAtom->getAddress() + ref->getFixUpOffset() + 1);
-                       }
-                       if ( (displacement > 127) || (displacement < (-128)) ) {
-                               //fprintf(stderr, "call out of range from %s in %s to %s in %s\n", this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath());
-                               throw "rel8 out of range";
-                       }
-                       *((int8_t*)fixUp) = (int8_t)displacement;
-                       break;
-               case x86_64::kPCRel32GOT:
-               case x86_64::kPCRel32GOTLoad:
-               case x86_64::kPCRel32GOTWeakImport:
-               case x86_64::kPCRel32GOTLoadWeakImport:
-                       // contains addend (usually zero)
-                       LittleEndian::set32(*((uint32_t*)fixUp), (uint32_t)(ref->getTargetOffset()));
-                       break;
-               case x86_64::kPointerDiff24:
-                       throw "internal linker error, kPointerDiff24 can't be encoded into object files";
-               case x86_64::kImageOffset32:
-                       throw "internal linker error, kImageOffset32 can't be encoded into object files";
-               case x86_64::kSectionOffset24:
-                       throw "internal linker error, kSectionOffset24 can't be encoded into object files";
-               case x86_64::kDtraceTypeReference:
-               case x86_64::kDtraceProbe:
-                       // nothing to fix up
-                       break;
-       }
-}
-
-template <>
-void Writer<ppc>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
-{
-       fixUpReference_powerpc(ref, inAtom, buffer, true);
-}
-
-template <>
-void Writer<ppc64>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
-{
-       fixUpReference_powerpc(ref, inAtom, buffer, true);
-}
-
-template <>
-void Writer<ppc>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
-{
-       fixUpReference_powerpc(ref, inAtom, buffer, false);
-}
-
-template <>
-void Writer<ppc64>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
-{
-       fixUpReference_powerpc(ref, inAtom, buffer, false);
-}
-
-//
-// ppc and ppc64 are mostly the same, so they share a template specialzation
-//
-template <typename A>
-void Writer<A>::fixUpReference_powerpc(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[], bool finalLinkedImage) const
-{
-       uint32_t        instruction;
-       uint32_t        newInstruction;
-       int64_t         displacement;
-       uint64_t        targetAddr = 0;
-       uint64_t        picBaseAddr;
-       uint16_t        instructionLowHalf;
-       uint16_t        instructionHighHalf;
-       uint32_t*       fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
-       pint_t*         fixUpPointer = (pint_t*)&buffer[ref->getFixUpOffset()];
-       bool            relocateableExternal = false;
-       const int64_t picbase_twoGigLimit = 0x80000000;
-
-       if ( ref->getTargetBinding() != ObjectFile::Reference::kDontBind ) {
-               targetAddr = ref->getTarget().getAddress() + ref->getTargetOffset();
-               if ( finalLinkedImage )
-                       relocateableExternal = (relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal);
-               else
-                       relocateableExternal = this->makesExternalRelocatableReference(ref->getTarget());       
-       }
-
-       switch ( (typename A::ReferenceKinds)(ref->getKind()) ) {
-               case A::kNoFixUp:
-               case A::kFollowOn:
-               case A::kGroupSubordinate:
-                       // do nothing
-                       break;
-               case A::kPointerWeakImport:
-               case A::kPointer:
-                       {
-                               //fprintf(stderr, "fixUpReferenceFinal: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
-                               if ( finalLinkedImage && (((SectionInfo*)inAtom->getSection())->fAllLazyPointers 
-                                                                          || ((SectionInfo*)inAtom->getSection())->fAllLazyDylibPointers) ) {
-                                       switch (ref->getTarget().getDefinitionKind()) {
-                                               case ObjectFile::Atom::kExternalDefinition:
-                                               case ObjectFile::Atom::kExternalWeakDefinition:
-                                                       // prebound lazy pointer to another dylib ==> pointer contains zero
-                                                       P::setP(*fixUpPointer, 0);
-                                                       break;
-                                               case ObjectFile::Atom::kTentativeDefinition:
-                                               case ObjectFile::Atom::kRegularDefinition:
-                                               case ObjectFile::Atom::kWeakDefinition:
-                                               case ObjectFile::Atom::kAbsoluteSymbol:
-                                                       // prebound lazy pointer to withing this dylib ==> pointer contains address
-                                                       P::setP(*fixUpPointer, targetAddr);
-                                                       break;
-                                       }
-                               }
-                               else if ( !finalLinkedImage && ((SectionInfo*)inAtom->getSection())->fAllNonLazyPointers ) {
-                                       // if INDIRECT_SYMBOL_LOCAL the content is pointer, else it is zero
-                                       if ( this->indirectSymbolInRelocatableIsLocal(ref) ) 
-                                               P::setP(*fixUpPointer, targetAddr);
-                                       else
-                                               P::setP(*fixUpPointer, 0);
-                               }
-                               else if ( relocateableExternal ) {
-                                       if ( fOptions.prebind() ) {
-                                               switch (ref->getTarget().getDefinitionKind()) {
-                                                       case ObjectFile::Atom::kExternalDefinition:
-                                                       case ObjectFile::Atom::kExternalWeakDefinition:
-                                                               // prebound external relocation ==> pointer contains addend
-                                                               P::setP(*fixUpPointer, ref->getTargetOffset());
-                                                               break;
-                                                       case ObjectFile::Atom::kTentativeDefinition:
-                                                       case ObjectFile::Atom::kRegularDefinition:
-                                                       case ObjectFile::Atom::kWeakDefinition:
-                                                               // prebound external relocation to internal atom ==> pointer contains target address + addend
-                                                               P::setP(*fixUpPointer, targetAddr);
-                                                               break;
-                                                       case ObjectFile::Atom::kAbsoluteSymbol:
-                                                               break;
-                                               }
-                                       } 
-                                       else {
-                                               // external relocation ==> pointer contains addend
-                                               P::setP(*fixUpPointer, ref->getTargetOffset());
-                                       }
-                               }
-                               else {
-                                       // internal relocation
-                                       if ( finalLinkedImage || (ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition)  ) {
-                                               // pointer contains target address
-                                               //printf("Atom::fixUpReference_powerpc() target.name=%s, target.address=0x%08llX\n",  ref->getTarget().getDisplayName(), targetAddr);
-                                               P::setP(*fixUpPointer, targetAddr);
-                                       }
-                                       else {
-                                               // pointer contains addend
-                                               P::setP(*fixUpPointer, ref->getTargetOffset());
-                                       }
-                               }
-                       }
-                       break;
-               case A::kPointerDiff64:
-                       P::setP(*fixUpPointer, targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
-                       break;
-               case A::kPointerDiff32:
-                       P::E::set32(*fixUp, targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
-                       break;
-               case A::kPointerDiff16:
-                       P::E::set16(*((uint16_t*)fixUp), targetAddr - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
-                       break;
-               case A::kDtraceProbeSite:
-                       if ( finalLinkedImage ) {
-                               // change call site to a NOP
-                               BigEndian::set32(*fixUp, 0x60000000);
-                       }
-                       else {
-                               // set  bl instuction to branch to address zero in .o file
-                               int64_t displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset());
-                               instruction = BigEndian::get32(*fixUp);
-                               newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
-                               BigEndian::set32(*fixUp, newInstruction);
-                       }
-                       break;
-               case A::kDtraceIsEnabledSite:
-                       if ( finalLinkedImage ) {
-                               // change call site to a li r3,0
-                               BigEndian::set32(*fixUp, 0x38600000);
-                       }
-                       else { 
-                               // set  bl instuction to branch to address zero in .o file
-                               int64_t displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset());
-                               instruction = BigEndian::get32(*fixUp);
-                               newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
-                               BigEndian::set32(*fixUp, newInstruction);
-                       }
-                       break;
-               case A::kBranch24WeakImport:
-               case A::kBranch24:
-                       {
-                               //fprintf(stderr, "bl fixup to %s at 0x%08llX, ", target.getDisplayName(), target.getAddress());
-                               int64_t displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
-                               if ( relocateableExternal )  {
-                                       // doing "ld -r" to an external symbol
-                                       // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
-                                       displacement -= ref->getTarget().getAddress();
-                               }
-                               else {
-                                       const int64_t bl_eightMegLimit = 0x00FFFFFF;
-                                       if ( (displacement > bl_eightMegLimit) || (displacement < (-bl_eightMegLimit)) ) {
-                                               //fprintf(stderr, "bl out of range (%lld max is +/-16M) from %s in %s to %s in %s\n", displacement, this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath());
-                                               throwf("bl out of range (%lld max is +/-16M) from %s at 0x%08llX in %s of %s to %s at 0x%08llX in %s of  %s",
-                                                       displacement, inAtom->getDisplayName(), inAtom->getAddress(), inAtom->getSectionName(), inAtom->getFile()->getPath(),
-                                                       ref->getTarget().getDisplayName(), ref->getTarget().getAddress(), ref->getTarget().getSectionName(), ref->getTarget().getFile()->getPath());
-                                       }
-                               }
-                               instruction = BigEndian::get32(*fixUp);
-                               newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
-                               //fprintf(stderr, "bl fixup: 0x%08X -> 0x%08X\n", instruction, newInstruction);
-                               BigEndian::set32(*fixUp, newInstruction);
-                       }
-                       break;
-               case A::kBranch14:
-                       {
-                               int64_t displacement = targetAddr - (inAtom->getAddress() + ref->getFixUpOffset());
-                               if ( relocateableExternal )  {
-                                       // doing "ld -r" to an external symbol
-                                       // the mach-o way of encoding this is that the bl instruction's target addr is the offset into the target
-                                       displacement -= ref->getTarget().getAddress();
-                               }
-                               const int64_t b_sixtyFourKiloLimit = 0x0000FFFF;
-                               if ( (displacement > b_sixtyFourKiloLimit) || (displacement < (-b_sixtyFourKiloLimit)) ) {
-                                       //fprintf(stderr, "bl out of range (%lld max is +/-16M) from %s in %s to %s in %s\n", displacement, this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath());
-                                       throwf("bcc out of range (%lld max is +/-64K) from %s in %s to %s in %s",
-                                               displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
-                                               ref->getTarget().getDisplayName(), ref->getTarget().getFile()->getPath());
-                               }
-                               
-                               //fprintf(stderr, "bcc fixup displacement=0x%08llX, atom.addr=0x%08llX, atom.offset=0x%08X\n", displacement, inAtom->getAddress(), (uint32_t)ref->getFixUpOffset());
-                               instruction = BigEndian::get32(*fixUp);
-                               newInstruction = (instruction & 0xFFFF0003) | ((uint32_t)displacement & 0x0000FFFC);
-                               //fprintf(stderr, "bc fixup: 0x%08X -> 0x%08X\n", instruction, newInstruction);
-                               BigEndian::set32(*fixUp, newInstruction);
-                       }
-                       break;
-               case A::kPICBaseLow16:
-                       picBaseAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
-                       displacement = targetAddr - picBaseAddr;
-                       if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
-                               throw "32-bit pic-base out of range";
-                       instructionLowHalf = (displacement & 0xFFFF);
-                       instruction = BigEndian::get32(*fixUp);
-                       newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
-                       BigEndian::set32(*fixUp, newInstruction);
-                       break;
-               case A::kPICBaseLow14:
-                       picBaseAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
-                       displacement = targetAddr - picBaseAddr;
-                       if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
-                               throw "32-bit pic-base out of range";
-                       if ( (displacement & 0x3) != 0 )
-                               throwf("bad offset (0x%08X) for lo14 instruction pic-base fix-up", (uint32_t)displacement);
-                       instructionLowHalf = (displacement & 0xFFFC);
-                       instruction = BigEndian::get32(*fixUp);
-                       newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf;
-                       BigEndian::set32(*fixUp, newInstruction);
-                       break;
-               case A::kPICBaseHigh16:
-                       picBaseAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
-                       displacement = targetAddr - picBaseAddr;
-                       if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
-                               throw "32-bit pic-base out of range";
-                       instructionLowHalf = displacement >> 16;
-                       if ( (displacement & 0x00008000) != 0 )
-                               ++instructionLowHalf;
-                       instruction = BigEndian::get32(*fixUp);
-                       newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
-                       BigEndian::set32(*fixUp, newInstruction);
-                       break;
-               case A::kAbsLow16:
-                       if ( relocateableExternal && !finalLinkedImage )
-                               targetAddr -= ref->getTarget().getAddress();
-                       instructionLowHalf = (targetAddr & 0xFFFF);
-                       instruction = BigEndian::get32(*fixUp);
-                       newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
-                       BigEndian::set32(*fixUp, newInstruction);
-                       break;
-               case A::kAbsLow14:
-                       if ( relocateableExternal && !finalLinkedImage )
-                               targetAddr -= ref->getTarget().getAddress();
-                       if ( (targetAddr & 0x3) != 0 )
-                               throw "bad address for absolute lo14 instruction fix-up";
-                       instructionLowHalf = (targetAddr & 0xFFFF);
-                       instruction = BigEndian::get32(*fixUp);
-                       newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf;
-                       BigEndian::set32(*fixUp, newInstruction);
-                       break;
-               case A::kAbsHigh16:
-                       if ( relocateableExternal ) {
-                               if ( finalLinkedImage ) {
-                                       switch (ref->getTarget().getDefinitionKind()) {
-                                               case ObjectFile::Atom::kExternalDefinition:
-                                               case ObjectFile::Atom::kExternalWeakDefinition:
-                                                       throwf("absolute address to symbol %s in a different linkage unit not supported", ref->getTargetName());
-                                                       break;
-                                               case ObjectFile::Atom::kTentativeDefinition:
-                                               case ObjectFile::Atom::kRegularDefinition:
-                                               case ObjectFile::Atom::kWeakDefinition:
-                                                       // use target address
-                                                       break;
-                                               case ObjectFile::Atom::kAbsoluteSymbol:
-                                                       targetAddr = ref->getTarget().getSectionOffset();
-                                                       break;
-                                       }
-                               }
-                               else {
-                                       targetAddr -= ref->getTarget().getAddress();
-                               }
-                       }
-                       instructionHighHalf = (targetAddr >> 16);
-                       instruction = BigEndian::get32(*fixUp);
-                       newInstruction = (instruction & 0xFFFF0000) | instructionHighHalf;
-                       BigEndian::set32(*fixUp, newInstruction);
-                       break;
-               case A::kAbsHigh16AddLow:
-                       if ( relocateableExternal ) {
-                               if ( finalLinkedImage ) {
-                                       switch (ref->getTarget().getDefinitionKind()) {
-                                               case ObjectFile::Atom::kExternalDefinition:
-                                               case ObjectFile::Atom::kExternalWeakDefinition:
-                                                       throwf("absolute address to symbol %s in a different linkage unit not supported", ref->getTargetName());
-                                                       break;
-                                               case ObjectFile::Atom::kTentativeDefinition:
-                                               case ObjectFile::Atom::kRegularDefinition:
-                                               case ObjectFile::Atom::kWeakDefinition:
-                                                       // use target address
-                                                       break;
-                                               case ObjectFile::Atom::kAbsoluteSymbol:
-                                                       targetAddr = ref->getTarget().getSectionOffset();
-                                                       break;
-                                       }
-                               }
-                               else {
-                                       targetAddr -= ref->getTarget().getAddress();
-                               }
-                       }
-                       if ( targetAddr & 0x00008000 )
-                               targetAddr += 0x00010000;
-                       instruction = BigEndian::get32(*fixUp);
-                       newInstruction = (instruction & 0xFFFF0000) | (targetAddr >> 16);
-                       BigEndian::set32(*fixUp, newInstruction);
-                       break;
-               case A::kDtraceTypeReference:
-               case A::kDtraceProbe:
-                       // nothing to fix up
-                       break;
-       }
-}
-
-template <>
-bool Writer<ppc>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
-{
-       uint8_t kind = ref->getKind();
-       switch ( (ppc::ReferenceKinds)kind ) {
-               case ppc::kNoFixUp:
-               case ppc::kFollowOn:
-               case ppc::kGroupSubordinate:
-               case ppc::kPointer:
-               case ppc::kPointerWeakImport:
-               case ppc::kPointerDiff16:
-               case ppc::kPointerDiff32:
-               case ppc::kPointerDiff64:
-               case ppc::kDtraceProbe:
-               case ppc::kDtraceProbeSite:
-               case ppc::kDtraceIsEnabledSite:
-               case ppc::kDtraceTypeReference:
-                       // these are never used to call external functions
-                       return false;
-               case ppc::kBranch24: 
-               case ppc::kBranch24WeakImport: 
-               case ppc::kBranch14: 
-                       // these are used to call external functions
-                       return true;
-               case ppc::kPICBaseLow16:
-               case ppc::kPICBaseLow14:
-               case ppc::kPICBaseHigh16:
-               case ppc::kAbsLow16:
-               case ppc::kAbsLow14:
-               case ppc::kAbsHigh16:
-               case ppc::kAbsHigh16AddLow:
-                       // these are only used to call external functions
-                       // in -mlong-branch stubs
-                       switch ( ref->getTarget().getDefinitionKind() ) {
-                               case ObjectFile::Atom::kExternalDefinition:
-                               case ObjectFile::Atom::kExternalWeakDefinition:
-                                       // if the .o file this atom came from has long-branch stubs,
-                                       // then assume these instructions in a stub.
-                                       // Otherwise, these are a direct reference to something (maybe a runtime text reloc)
-                                       return ( inAtom->getFile()->hasLongBranchStubs() );
-                               case ObjectFile::Atom::kTentativeDefinition:
-                               case ObjectFile::Atom::kRegularDefinition:
-                               case ObjectFile::Atom::kWeakDefinition:
-                               case ObjectFile::Atom::kAbsoluteSymbol:
-                                       return false;
-                       }
-                       break;
-       }
-       return false;
-}
-
-template <>
-bool Writer<arm>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
-{
-       uint8_t kind = ref->getKind();
-       switch ( (arm::ReferenceKinds)kind ) {
-               case arm::kBranch24:
-               case arm::kBranch24WeakImport:
-                       return true;
-               case arm::kThumbBranch22:
-               case arm::kThumbBranch22WeakImport:
-                       fHasThumbBranches = true;
-                       return true;
-               case arm::kNoFixUp:
-               case arm::kFollowOn:
-               case arm::kGroupSubordinate:
-               case arm::kPointer:
-               case arm::kReadOnlyPointer:
-               case arm::kPointerWeakImport:
-               case arm::kPointerDiff:
-               case arm::kDtraceProbe:
-               case arm::kDtraceProbeSite:
-               case arm::kDtraceIsEnabledSite:
-               case arm::kDtraceTypeReference:
-               case arm::kPointerDiff12:
-                       return false;
-       }
-       return false;
-}
-
-template <>
-bool Writer<ppc64>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
-{
-       uint8_t kind = ref->getKind();
-       switch ( (ppc64::ReferenceKinds)kind ) {
-               case ppc::kNoFixUp:
-               case ppc::kFollowOn:
-               case ppc::kGroupSubordinate:
-               case ppc::kPointer:
-               case ppc::kPointerWeakImport:
-               case ppc::kPointerDiff16:
-               case ppc::kPointerDiff32:
-               case ppc::kPointerDiff64:
-               case ppc::kPICBaseLow16:
-               case ppc::kPICBaseLow14:
-               case ppc::kPICBaseHigh16:
-               case ppc::kAbsLow16:
-               case ppc::kAbsLow14:
-               case ppc::kAbsHigh16:
-               case ppc::kAbsHigh16AddLow:
-               case ppc::kDtraceProbe:
-               case ppc::kDtraceProbeSite:
-               case ppc::kDtraceIsEnabledSite:
-               case ppc::kDtraceTypeReference:
-                       // these are never used to call external functions
-                       return false;
-               case ppc::kBranch24: 
-               case ppc::kBranch24WeakImport: 
-               case ppc::kBranch14: 
-                       // these are used to call external functions
-                       return true;
-       }
-       return false;
-}
-
-template <>
-bool Writer<x86>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
-{
-       uint8_t kind = ref->getKind();
-       return (kind == x86::kPCRel32 || kind == x86::kPCRel32WeakImport);
-}
-
-template <>
-bool Writer<x86_64>::stubableReference(const ObjectFile::Atom* inAtom, const ObjectFile::Reference* ref)
-{
-       uint8_t kind = ref->getKind();
-       return (kind == x86_64::kBranchPCRel32 || kind == x86_64::kBranchPCRel32WeakImport);
-}
-
-
-template <>
-bool Writer<ppc>::weakImportReferenceKind(uint8_t kind)
-{
-       return (kind == ppc::kBranch24WeakImport || kind == ppc::kPointerWeakImport);
-}
-
-template <>
-bool Writer<ppc64>::weakImportReferenceKind(uint8_t kind)
-{
-       return (kind == ppc64::kBranch24WeakImport || kind == ppc64::kPointerWeakImport);
-}
-
-template <>
-bool Writer<x86>::weakImportReferenceKind(uint8_t kind)
-{
-       return (kind == x86::kPCRel32WeakImport || kind == x86::kPointerWeakImport);
-}
-
-template <>
-bool Writer<x86_64>::weakImportReferenceKind(uint8_t kind)
-{
-       switch ( kind ) {
-               case x86_64::kPointerWeakImport:
-               case x86_64::kBranchPCRel32WeakImport:
-               case x86_64::kPCRel32GOTWeakImport:
-               case x86_64::kPCRel32GOTLoadWeakImport:
-                       return true;
-       }
-       return false;
-}
-
-template <>
-bool Writer<arm>::weakImportReferenceKind(uint8_t kind)
-{
-       return (kind == arm::kBranch24WeakImport || kind == arm::kThumbBranch22WeakImport ||
-            kind == arm::kPointerWeakImport);
-}
-
-template <>
-bool Writer<ppc>::GOTReferenceKind(uint8_t kind)
-{
-       return false;
-}
-
-template <>
-bool Writer<ppc64>::GOTReferenceKind(uint8_t kind)
-{
-       return false;
-}
-
-template <>
-bool Writer<x86>::GOTReferenceKind(uint8_t kind)
-{
-       return false;
-}
-
-template <>
-bool Writer<x86_64>::GOTReferenceKind(uint8_t kind)
-{
-       switch ( kind ) {
-               case x86_64::kPCRel32GOT:
-               case x86_64::kPCRel32GOTWeakImport:
-               case x86_64::kPCRel32GOTLoad:
-               case x86_64::kPCRel32GOTLoadWeakImport:
-               case x86_64::kGOTNoFixUp:
-                       return true;
-       }
-       return false;
-}
-
-template <>
-bool Writer<arm>::GOTReferenceKind(uint8_t kind)
-{
-       return false;
-}
-
-template <>
-bool Writer<ppc>::optimizableGOTReferenceKind(uint8_t kind)
-{
-       return false;
-}
-
-template <>
-bool Writer<ppc64>::optimizableGOTReferenceKind(uint8_t kind)
-{
-       return false;
-}
-
-template <>
-bool Writer<x86>::optimizableGOTReferenceKind(uint8_t kind)
-{
-       return false;
-}
-
-template <>
-bool Writer<x86_64>::optimizableGOTReferenceKind(uint8_t kind)
-{
-       switch ( kind ) {
-               case x86_64::kPCRel32GOTLoad:
-               case x86_64::kPCRel32GOTLoadWeakImport:
-                       return true;
-       }
-       return false;
-}
-
-template <>
-bool Writer<arm>::optimizableGOTReferenceKind(uint8_t kind)
-{
-       return false;
-}
-
-// 64-bit architectures never need module table, 32-bit sometimes do for backwards compatiblity
-template <typename A> bool Writer<A>::needsModuleTable() {return fOptions.needsModuleTable(); }
-template <> bool Writer<ppc64>::needsModuleTable() { return false; }
-template <> bool Writer<x86_64>::needsModuleTable() { return false; }
-
-
-template <typename A>
-void Writer<A>::optimizeDylibReferences()
-{
-       //fprintf(stderr, "original ordinals table:\n");
-       //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
-       //      fprintf(stderr, "%u <== %p/%s\n", it->second, it->first, it->first->getPath());
-       //}
-       // find unused dylibs that can be removed
-       std::map<uint32_t, ObjectFile::Reader*> ordinalToReader;
-       std::map<ObjectFile::Reader*, ObjectFile::Reader*> readerAliases;
-       for (std::map<ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {   
-               ObjectFile::Reader* reader = it->first;
-               std::map<ObjectFile::Reader*, ObjectFile::Reader*>::iterator aliasPos = fLibraryAliases.find(reader);
-               if ( aliasPos != fLibraryAliases.end() ) {
-                       // already noticed that this reader has same install name as another reader
-                       readerAliases[reader] = aliasPos->second;
-               }
-               else if ( !reader->providedExportAtom() && (reader->implicitlyLinked() || reader->deadStrippable() || fOptions.deadStripDylibs()) ) {
-                       // this reader can be optimized away
-                       it->second = 0xFFFFFFFF;
-                       typename std::map<class ObjectFile::Reader*, class DylibLoadCommandsAtom<A>* >::iterator pos = fLibraryToLoadCommand.find(reader);
-                       if ( pos != fLibraryToLoadCommand.end() ) 
-                               pos->second->optimizeAway();
-               }
-               else {
-                       // mark this reader as using it ordinal
-                       std::map<uint32_t, ObjectFile::Reader*>::iterator pos = ordinalToReader.find(it->second);
-                       if ( pos == ordinalToReader.end() ) 
-                               ordinalToReader[it->second] = reader;
-                       else
-                               readerAliases[reader] = pos->second;
-               }
-       }
-       // renumber ordinals (depends on iterator walking in ordinal order)
-       // all LC_LAZY_LOAD_DYLIB load commands must have highest ordinals
-       uint32_t newOrdinal = 0;
-       for (std::map<uint32_t, ObjectFile::Reader*>::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) {
-               if ( it->first <= fLibraryToOrdinal.size() ) {
-                       if ( ! it->second->isLazyLoadedDylib() )
-                               fLibraryToOrdinal[it->second] = ++newOrdinal;
-               }
-       }
-       for (std::map<uint32_t, ObjectFile::Reader*>::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) {
-               if ( it->first <= fLibraryToOrdinal.size() ) {
-                       if ( it->second->isLazyLoadedDylib() ) {
-                               fLibraryToOrdinal[it->second] = ++newOrdinal;
-                       }
-               }
-       }
-       
-       // <rdar://problem/5504954> linker does not error when dylib ordinal exceeds 250
-       if ( (newOrdinal >= MAX_LIBRARY_ORDINAL) && (fOptions.nameSpace() == Options::kTwoLevelNameSpace) )
-               throwf("two level namespace mach-o files can link with at most %d dylibs, this link would use %d dylibs", MAX_LIBRARY_ORDINAL, newOrdinal);
-
-       // add aliases (e.g. -lm points to libSystem.dylib)
-       for (std::map<ObjectFile::Reader*, ObjectFile::Reader*>::iterator it = readerAliases.begin(); it != readerAliases.end(); ++it) {
-               fLibraryToOrdinal[it->first] = fLibraryToOrdinal[it->second];
-       }
-
-       //fprintf(stderr, "new ordinals table:\n");
-       //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
-       //      fprintf(stderr, "%u <== %p/%s\n", it->second, it->first, it->first->getPath());
-       //}
-}
-
-
-template <>
-void Writer<arm>::scanForAbsoluteReferences()
-{
-       // arm codegen never has absolute references.  FIXME: Is this correct?
-}
-
-template <>
-void Writer<x86_64>::scanForAbsoluteReferences()
-{
-       // x86_64 codegen never has absolute references
-}
-
-template <>
-void  Writer<x86>::scanForAbsoluteReferences()
-{
-       // when linking -pie verify there are no absolute addressing, unless -read_only_relocs is also used
-       if ( fOptions.positionIndependentExecutable() && !fOptions.allowTextRelocs() ) {
-               for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
-                       ObjectFile::Atom* atom = *it;
-                       if ( atom->getContentType() == ObjectFile::Atom::kStub )
-                               continue;
-                       if ( atom->getContentType() == ObjectFile::Atom::kStubHelper )
-                               continue;
-                       std::vector<ObjectFile::Reference*>&  references = atom->getReferences();
-                       for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
-                               ObjectFile::Reference* ref = *rit;
-                               switch (ref->getKind()) {
-                                       case x86::kAbsolute32:
-                                               throwf("cannot link -pie: -mdynamic-no-pic codegen found in %s from %s", atom->getDisplayName(), atom->getFile()->getPath());
-                                               return;
-                               }
-                       }
-               }
-       }
-}
-
-template <>
-void  Writer<ppc>::scanForAbsoluteReferences()
-{
-       // when linking -pie verify there are no absolute addressing, unless -read_only_relocs is also used
-       if ( fOptions.positionIndependentExecutable()  && !fOptions.allowTextRelocs() ) {
-               for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
-                       ObjectFile::Atom* atom = *it;
-                       std::vector<ObjectFile::Reference*>&  references = atom->getReferences();
-                       for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
-                               ObjectFile::Reference* ref = *rit;
-                               switch (ref->getKind()) {
-                                       case ppc::kAbsLow16:
-                                       case ppc::kAbsLow14:
-                                       case ppc::kAbsHigh16:
-                                       case ppc::kAbsHigh16AddLow:
-                                               throwf("cannot link -pie: -mdynamic-no-pic codegen found in %s from %s", atom->getDisplayName(), atom->getFile()->getPath());
-                                               return;
-                               }
-                       }
-               }
-       }
-}
-
-
-// for ppc64 look for any -mdynamic-no-pic codegen
-template <>
-void  Writer<ppc64>::scanForAbsoluteReferences()
-{
-       // only do this for main executable
-       if ( mightNeedPadSegment() && (fPageZeroAtom != NULL) ) {
-               for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
-                       ObjectFile::Atom* atom = *it;
-                       std::vector<ObjectFile::Reference*>&  references = atom->getReferences();
-                       for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
-                               ObjectFile::Reference* ref = *rit;
-                               switch (ref->getKind()) {
-                                       case ppc64::kAbsLow16:
-                                       case ppc64::kAbsLow14:
-                                       case ppc64::kAbsHigh16:
-                                       case ppc64::kAbsHigh16AddLow:
-                                               //fprintf(stderr, "found -mdynamic-no-pic codegen in %s in %s\n", atom->getDisplayName(), atom->getFile()->getPath());
-                                               // shrink page-zero and add pad segment to compensate
-                                               fPadSegmentInfo = new SegmentInfo(4096);
-                                               strcpy(fPadSegmentInfo->fName, "__4GBFILL");
-                                               fPageZeroAtom->setSize(0x1000);
-                                               return;
-                               }
-                       }
-               }
-       }
-}
-
-               
-template <typename A>
-void Writer<A>::insertDummyStubs()
-{
-       // only needed for x86
-}
-
-template <>
-void Writer<x86>::insertDummyStubs()
-{
-       // any 5-byte stubs that cross a 32-byte cache line may update incorrectly
-       std::vector<class StubAtom<x86>*>        betterStubs;
-       for (std::vector<class StubAtom<x86>*>::iterator it=fAllSynthesizedStubs.begin(); it != fAllSynthesizedStubs.end(); it++) {
-               switch (betterStubs.size() % 64 ) {
-                       case 12:// stub would occupy 0x3C->0x41
-                       case 25:// stub would occupy 0x7D->0x82
-                       case 38:// stub would occupy 0xBE->0xC3
-                       case 51:// stub would occupy 0xFF->0x04
-                               betterStubs.push_back(new StubAtom<x86>(*this, *((ObjectFile::Atom*)NULL), false)); //pad with dummy stub
-                               break;
-               }
-               betterStubs.push_back(*it);
-       }
-       // replace 
-       fAllSynthesizedStubs.clear();
-       fAllSynthesizedStubs.insert(fAllSynthesizedStubs.begin(), betterStubs.begin(), betterStubs.end());
-}
-
-
-template <typename A>
-void Writer<A>::synthesizeKextGOT(const std::vector<class ObjectFile::Atom*>& existingAtoms,
-                                                                       std::vector<class ObjectFile::Atom*>& newAtoms)
-{
-       // walk every atom and reference
-       for (std::vector<ObjectFile::Atom*>::const_iterator it=existingAtoms.begin(); it != existingAtoms.end(); it++) {
-               const ObjectFile::Atom* atom = *it;
-               std::vector<ObjectFile::Reference*>&  references = atom->getReferences();
-               for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
-                       ObjectFile::Reference* ref = *rit;
-                       switch ( ref->getTargetBinding()) {
-                               case ObjectFile::Reference::kUnboundByName:
-                               case ObjectFile::Reference::kDontBind:
-                                       break;
-                               case ObjectFile::Reference::kBoundByName:
-                               case ObjectFile::Reference::kBoundDirectly:
-                                       ObjectFile::Atom& target = ref->getTarget();
-                                       // create GOT slots (non-lazy pointers) as needed
-                                       if ( this->GOTReferenceKind(ref->getKind()) ) {
-                                               bool useGOT = ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal );
-                                               // if this GOT usage cannot be optimized away then make a GOT enry
-                                               if ( ! this->optimizableGOTReferenceKind(ref->getKind()) )
-                                                       useGOT = true;
-                                               if ( useGOT ) {
-                                                       ObjectFile::Atom* nlp = NULL;
-                                                       std::map<ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fGOTMap.find(&target);
-                                                       if ( pos == fGOTMap.end() ) {
-                                                               nlp = new NonLazyPointerAtom<A>(*this, target);
-                                                               fGOTMap[&target] = nlp;
-                                                               newAtoms.push_back(nlp);
-                                                       }
-                                                       else {
-                                                               nlp = pos->second;
-                                                       }
-                                                       // alter reference to use non lazy pointer instead
-                                                       ref->setTarget(*nlp, ref->getTargetOffset());
-                                               }
-                                       }
-                                       // build map of which symbols need weak importing
-                                       if ( (target.getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
-                                               || (target.getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
-                                               if ( this->weakImportReferenceKind(ref->getKind()) ) {
-                                                       fWeakImportMap[&target] = true;
-                                               }
-                                       }
-                                       break;
-                       }
-               }
-       }
-}
-
-
-template <typename A>
-void Writer<A>::synthesizeStubs(const std::vector<class ObjectFile::Atom*>& existingAtoms,
-                                                                       std::vector<class ObjectFile::Atom*>& newAtoms)
-{
-       switch ( fOptions.outputKind() ) {
-               case Options::kObjectFile:
-               case Options::kPreload:
-                       // these output kinds never have stubs
-                       return;
-               case Options::kKextBundle:
-                       // new kext need a synthesized GOT only
-                       synthesizeKextGOT(existingAtoms, newAtoms);
-                       return;
-               case Options::kStaticExecutable:
-               case Options::kDyld:
-               case Options::kDynamicLibrary:
-               case Options::kDynamicBundle:
-               case Options::kDynamicExecutable:
-                       // try to synthesize stubs for these
-                       break;
-       }
-
-       // walk every atom and reference
-       for (std::vector<ObjectFile::Atom*>::const_iterator it=existingAtoms.begin(); it != existingAtoms.end(); it++) {
-               ObjectFile::Atom* atom = *it;
-               std::vector<ObjectFile::Reference*>&  references = atom->getReferences();
-               for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
-                       ObjectFile::Reference* ref = *rit;
-                       switch ( ref->getTargetBinding()) {
-                               case ObjectFile::Reference::kUnboundByName:
-                               case ObjectFile::Reference::kDontBind:
-                                       break;
-                               case ObjectFile::Reference::kBoundByName:
-                               case ObjectFile::Reference::kBoundDirectly:
-                                       ObjectFile::Atom& target = ref->getTarget();
-                                       // build map of which symbols need weak importing
-                                       if ( (target.getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
-                                               || (target.getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
-                                               bool weakImport = this->weakImportReferenceKind(ref->getKind());
-                                               // <rdar://problem/5633081> Obj-C Symbols in Leopard Can't Be Weak Linked
-                                               // dyld in Mac OS X 10.3 and earlier need N_WEAK_REF bit set on undefines to objc symbols
-                                               // in dylibs that are weakly linked.  
-                                               if ( (ref->getKind() == A::kNoFixUp) && (strncmp(target.getName(), ".objc_class_name_", 17) == 0) ) {
-                                                       typename std::map<class ObjectFile::Reader*, class DylibLoadCommandsAtom<A>* >::iterator pos;
-                                                       pos = fLibraryToLoadCommand.find(target.getFile());
-                                                       if ( pos != fLibraryToLoadCommand.end() ) {
-                                                               if ( pos->second->linkedWeak() )
-                                                                       weakImport = true;
-                                                       }
-                                               }
-                                               // <rdar://problem/6186838> -weak_library no longer forces uses to be weak_import
-                                               if ( fForcedWeakImportReaders.count(target.getFile()) != 0 ) {
-                                                       fWeakImportMap[&target] = true;
-                                                       weakImport = true;
-                                               }
-                                               
-                                               std::map<const ObjectFile::Atom*,bool>::iterator pos = fWeakImportMap.find(&target);
-                                               if ( pos == fWeakImportMap.end() ) {
-                                                       // target not in fWeakImportMap, so add
-                                                       fWeakImportMap[&target] = weakImport;
-                                               }
-                                               else {
-                                                       // target in fWeakImportMap, check for weakness mismatch
-                                                       if ( pos->second != weakImport ) {
-                                                               // found mismatch
-                                                               switch ( fOptions.weakReferenceMismatchTreatment() ) {
-                                                                       case Options::kWeakReferenceMismatchError:
-                                                                               throwf("mismatching weak references for symbol: %s", target.getName());
-                                                                       case Options::kWeakReferenceMismatchWeak:
-                                                                               pos->second = true;
-                                                                               break;
-                                                                       case Options::kWeakReferenceMismatchNonWeak:
-                                                                               pos->second = false;
-                                                                               break;
-                                                               }
-                                                       }
-                                               }
-                                               // update if we use a weak_import or a strong import from this dylib
-                                               if ( fWeakImportMap[&target] )
-                                                       fDylibReadersWithWeakImports.insert(target.getFile());
-                                               else
-                                                       fDylibReadersWithNonWeakImports.insert(target.getFile());
-                                       }
-                                       // create stubs as needed
-                                       if ( this->stubableReference(atom, ref) 
-                                               && (ref->getTargetOffset() == 0)
-                                               && this->relocationNeededInFinalLinkedImage(target) == kRelocExternal ) {
-                                               ObjectFile::Atom* stub = NULL;
-                                               std::map<const ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fStubsMap.find(&target);
-                                               if ( pos == fStubsMap.end() ) {
-                                                       bool forLazyDylib = false;
-                                                       switch ( target.getDefinitionKind() ) {
-                                                               case ObjectFile::Atom::kRegularDefinition:
-                                                               case ObjectFile::Atom::kWeakDefinition:
-                                                               case ObjectFile::Atom::kAbsoluteSymbol:
-                                                               case ObjectFile::Atom::kTentativeDefinition:
-                                                                       break;
-                                                               case ObjectFile::Atom::kExternalDefinition:
-                                                               case ObjectFile::Atom::kExternalWeakDefinition:
-                                                                       if ( target.getFile()->isLazyLoadedDylib() )
-                                                                               forLazyDylib = true;
-                                                                       break;
-                                                       }
-                                                       // just-in-time, create GOT slot to dyld_stub_binder
-                                                       if ( fOptions.makeCompressedDyldInfo() && (fFastStubGOTAtom == NULL) ) {
-                                                               if ( fDyldCompressedHelperAtom == NULL )
-                                                                       throw "missing symbol dyld_stub_binder";
-                                                               fFastStubGOTAtom = new NonLazyPointerAtom<A>(*this, *fDyldCompressedHelperAtom);
-                                                       }
-                                                       stub = new StubAtom<A>(*this, target, forLazyDylib);
-                                                       fStubsMap[&target] = stub;
-                                               }
-                                               else {
-                                                       stub = pos->second;
-                                               }
-                                               // alter reference to use stub instead
-                                               ref->setTarget(*stub, 0);
-                                       }
-                                       else if ( fOptions.usingLazyDylibLinking() && target.getFile()->isLazyLoadedDylib() ) {
-                                               throwf("illegal reference to %s in lazy loaded dylib from %s in %s", 
-                                                               target.getDisplayName(), atom->getDisplayName(), 
-                                                               atom->getFile()->getPath());
-                                       }
-                                       // create GOT slots (non-lazy pointers) as needed
-                                       else if ( this->GOTReferenceKind(ref->getKind()) ) {
-                                               // 
-                                               bool mustUseGOT = ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal );
-                                               bool useGOT;
-                                               if ( fBiggerThanTwoGigs ) {
-                                                       // in big images use GOT for all zero fill atoms
-                                                       // this is just a heuristic and may need to be re-examined
-                                                       useGOT = mustUseGOT || ref->getTarget().isZeroFill();
-                                               }
-                                               else {
-                                                       // < 2GB image so remove all GOT entries that we can
-                                                       useGOT = mustUseGOT;
-                                               }
-                                               // if this GOT usage cannot be optimized away then make a GOT enry
-                                               if ( ! this->optimizableGOTReferenceKind(ref->getKind()) )
-                                                       useGOT = true;
-                                               if ( useGOT ) {
-                                                       ObjectFile::Atom* nlp = NULL;
-                                                       std::map<ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fGOTMap.find(&target);
-                                                       if ( pos == fGOTMap.end() ) {
-                                                               nlp = new NonLazyPointerAtom<A>(*this, target);
-                                                               fGOTMap[&target] = nlp;
-                                                       }
-                                                       else {
-                                                               nlp = pos->second;
-                                                       }
-                                                       // alter reference to use non lazy pointer instead
-                                                       ref->setTarget(*nlp, ref->getTargetOffset());
-                                               }
-                                       }
-                       }
-               }
-       }
-
-       // sort stubs
-       std::sort(fAllSynthesizedStubs.begin(), fAllSynthesizedStubs.end(), AtomByNameSorter());
-       // add dummy self-modifying stubs (x86 only)
-       if ( ! fOptions.makeCompressedDyldInfo() )      
-               this->insertDummyStubs();
-       // set ordinals so sorting is preserved
-       uint32_t sortOrder = 0;
-       for (typename std::vector<StubAtom<A>*>::iterator it=fAllSynthesizedStubs.begin(); it != fAllSynthesizedStubs.end(); it++) 
-               (*it)->setSortingOrdinal(sortOrder++);
-       std::sort(fAllSynthesizedStubHelpers.begin(), fAllSynthesizedStubHelpers.end(), AtomByNameSorter());
-
-       // sort lazy pointers
-       std::sort(fAllSynthesizedLazyPointers.begin(), fAllSynthesizedLazyPointers.end(), AtomByNameSorter());
-       sortOrder = 0;
-       for (typename std::vector<LazyPointerAtom<A>*>::iterator it=fAllSynthesizedLazyPointers.begin(); it != fAllSynthesizedLazyPointers.end(); it++) 
-               (*it)->setSortingOrdinal(sortOrder++);
-       std::sort(fAllSynthesizedLazyDylibPointers.begin(), fAllSynthesizedLazyDylibPointers.end(), AtomByNameSorter());
-       
-       // sort non-lazy pointers
-       std::sort(fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end(), AtomByNameSorter());
-       sortOrder = 0;
-       for (typename std::vector<NonLazyPointerAtom<A>*>::iterator it=fAllSynthesizedNonLazyPointers.begin(); it != fAllSynthesizedNonLazyPointers.end(); it++) 
-               (*it)->setSortingOrdinal(sortOrder++);
-       std::sort(fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end(), AtomByNameSorter());
-
-       // tell linker about all synthesized atoms
-       newAtoms.insert(newAtoms.end(), fAllSynthesizedStubs.begin(), fAllSynthesizedStubs.end());
-       newAtoms.insert(newAtoms.end(), fAllSynthesizedStubHelpers.begin(), fAllSynthesizedStubHelpers.end());
-       newAtoms.insert(newAtoms.end(), fAllSynthesizedLazyPointers.begin(), fAllSynthesizedLazyPointers.end());
-       newAtoms.insert(newAtoms.end(), fAllSynthesizedLazyDylibPointers.begin(), fAllSynthesizedLazyDylibPointers.end());
-       newAtoms.insert(newAtoms.end(), fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end());
-       
-}
-
-template <typename A>
-void Writer<A>::createSplitSegContent()
-{
-       // build LC_SEGMENT_SPLIT_INFO once all atoms exist
-       if ( fSplitCodeToDataContentAtom != NULL ) {
-               for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
-                       ObjectFile::Atom* atom = *it;
-                       std::vector<ObjectFile::Reference*>&  references = atom->getReferences();
-                       for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
-                               ObjectFile::Reference* ref = *rit;
-                               switch ( ref->getTargetBinding()) {
-                                       case ObjectFile::Reference::kUnboundByName:
-                                       case ObjectFile::Reference::kDontBind:
-                                               break;
-                                       case ObjectFile::Reference::kBoundByName:
-                                       case ObjectFile::Reference::kBoundDirectly:
-                                               if ( this->segmentsCanSplitApart(*atom, ref->getTarget()) ) {
-                                                       this->addCrossSegmentRef(atom, ref);
-                                               }
-                                               break;
-                               }
-                       }
-               }
-               // bad codegen may cause LC_SEGMENT_SPLIT_INFO to be removed
-               adjustLoadCommandsAndPadding();
-       }
-
-}
-
-
-template <typename A>
-void Writer<A>::synthesizeUnwindInfoTable()
-{
-       if ( fUnwindInfoAtom != NULL ) {
-               // walk every atom and gets its unwind info
-               for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
-                       ObjectFile::Atom* atom = *it;
-                       if ( atom->beginUnwind() == atom->endUnwind() ) {
-                               // be sure to mark that we have no unwind info for stuff in the TEXT segment without unwind info
-                               if ( strcmp(atom->getSegment().getName(), "__TEXT") == 0 )
-                                       fUnwindInfoAtom->addUnwindInfo(atom, 0, 0, NULL, NULL, NULL);
-                       }
-                       else {
-                               // atom has unwind 
-                               for ( ObjectFile::UnwindInfo::iterator uit = atom->beginUnwind(); uit != atom->endUnwind(); ++uit ) {
-                                       fUnwindInfoAtom->addUnwindInfo(atom, uit->startOffset, uit->unwindInfo, atom->getFDE(), atom->getLSDA(), atom->getPersonalityPointer());
-                               }
-                       }
-               }
-       }
-}
-
-
-template <typename A>
-void Writer<A>::partitionIntoSections()
-{
-       const bool oneSegmentCommand = (fOptions.outputKind() == Options::kObjectFile);
-
-       // for every atom, set its sectionInfo object and section offset
-       // build up fSegmentInfos along the way
-       ObjectFile::Section* curSection = (ObjectFile::Section*)(-1);
-       SectionInfo* currentSectionInfo = NULL;
-       SegmentInfo* currentSegmentInfo = NULL;
-       SectionInfo* cstringSectionInfo = NULL;
-       unsigned int sectionIndex = 1;
-       fSegmentInfos.reserve(8);
-       for (unsigned int i=0; i < fAllAtoms->size(); ++i) {
-               ObjectFile::Atom* atom = (*fAllAtoms)[i];
-               if ( ((atom->getSection() != curSection) || (curSection==NULL)) 
-                       && ((currentSectionInfo == NULL) 
-                               || (strcmp(atom->getSectionName(),currentSectionInfo->fSectionName) != 0) 
-                               || (strcmp(atom->getSegment().getName(),currentSectionInfo->fSegmentName) != 0)) ) {
-                       if ( oneSegmentCommand ) {
-                               if ( currentSegmentInfo == NULL ) {
-                                       currentSegmentInfo = new SegmentInfo(fOptions.segmentAlignment());
-                                       currentSegmentInfo->fInitProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
-                                       currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
-                                       this->fSegmentInfos.push_back(currentSegmentInfo);
-                               }
-                               currentSectionInfo = new SectionInfo();
-                               strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
-                               strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
-                               currentSectionInfo->fAlignment = atom->getAlignment().powerOf2;
-                               currentSectionInfo->fAllZeroFill = atom->isZeroFill();
-                               currentSectionInfo->fVirtualSection = (currentSectionInfo->fSectionName[0] == '.');
-                               if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
-                                       currentSectionInfo->setIndex(sectionIndex++);
-                               currentSegmentInfo->fSections.push_back(currentSectionInfo);
-                               if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__cstring") == 0) ) 
-                                       cstringSectionInfo = currentSectionInfo;
-                       }
-                       else {
-                               if ( (currentSegmentInfo == NULL) || (strcmp(currentSegmentInfo->fName, atom->getSegment().getName()) != 0) ) {
-                                       currentSegmentInfo = new SegmentInfo(fOptions.segmentAlignment());
-                                       strcpy(currentSegmentInfo->fName, atom->getSegment().getName());
-                                       uint32_t initprot  = 0;
-                                       if ( atom->getSegment().isContentReadable() )
-                                               initprot |= VM_PROT_READ;
-                                       if ( atom->getSegment().isContentWritable() )
-                                               initprot |= VM_PROT_WRITE;
-                                       if ( atom->getSegment().isContentExecutable() )
-                                               initprot |= VM_PROT_EXECUTE;
-                                       if ( fOptions.readOnlyx86Stubs() && (strcmp(atom->getSegment().getName(), "__IMPORT") == 0) )
-                                               initprot &= ~VM_PROT_WRITE;     // hack until i386 __pointers section is synthesized by linker
-                                       currentSegmentInfo->fInitProtection = initprot;
-                                       if ( initprot == 0 )
-                                               currentSegmentInfo->fMaxProtection = 0;  // pagezero should have maxprot==initprot==0
-                                       else if ( fOptions.architecture() == CPU_TYPE_ARM )
-                                               currentSegmentInfo->fMaxProtection = currentSegmentInfo->fInitProtection; // iPhoneOS wants max==init
-                                       else
-                                               currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
-                                       std::vector<Options::SegmentProtect>& customSegProtections = fOptions.customSegmentProtections();
-                                       for(std::vector<Options::SegmentProtect>::iterator it = customSegProtections.begin(); it != customSegProtections.end(); ++it) {
-                                               if ( strcmp(it->name, currentSegmentInfo->fName) == 0 ) {
-                                                       currentSegmentInfo->fInitProtection = it->init;
-                                                       currentSegmentInfo->fMaxProtection = it->max;
-                                               }
-                                       }
-                                       currentSegmentInfo->fBaseAddress = atom->getSegment().getBaseAddress();
-                                       currentSegmentInfo->fFixedAddress = atom->getSegment().hasFixedAddress();
-                                       if ( currentSegmentInfo->fFixedAddress && (&(atom->getSegment()) == &Segment::fgStackSegment) )
-                                               currentSegmentInfo->fIndependentAddress = true;
-                                       if ( (fOptions.outputKind() == Options::kPreload) && (strcmp(currentSegmentInfo->fName, "__LINKEDIT")==0) )
-                                               currentSegmentInfo->fHasLoadCommand = false;
-                                       if ( strcmp(currentSegmentInfo->fName, "__HEADER")==0 )
-                                               currentSegmentInfo->fHasLoadCommand = false;
-                                       this->fSegmentInfos.push_back(currentSegmentInfo);
-                               }
-                               currentSectionInfo = new SectionInfo();
-                               currentSectionInfo->fAtoms.reserve(fAllAtoms->size()/4); // reduce reallocations by starting large
-                               strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
-                               strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
-                               currentSectionInfo->fAlignment = atom->getAlignment().powerOf2;
-                               // check for -sectalign override
-                               std::vector<Options::SectionAlignment>& alignmentOverrides = fOptions.sectionAlignments();
-                               for(std::vector<Options::SectionAlignment>::iterator it=alignmentOverrides.begin(); it != alignmentOverrides.end(); ++it) {
-                                       if ( (strcmp(it->segmentName, currentSectionInfo->fSegmentName) == 0) && (strcmp(it->sectionName, currentSectionInfo->fSectionName) == 0) )
-                                               currentSectionInfo->fAlignment = it->alignment;
-                               }
-                               currentSectionInfo->fAllZeroFill = atom->isZeroFill();
-                               currentSectionInfo->fVirtualSection = ( currentSectionInfo->fSectionName[0] == '.');
-                               if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
-                                       currentSectionInfo->setIndex(sectionIndex++);
-                               currentSegmentInfo->fSections.push_back(currentSectionInfo);
-                       }
-                       //fprintf(stderr, "new section %s for atom %s\n", atom->getSectionName(), atom->getDisplayName());
-                       if ( strcmp(currentSectionInfo->fSectionName, "._load_commands") == 0 ) {
-                               fLoadCommandsSection = currentSectionInfo;
-                               fLoadCommandsSegment = currentSegmentInfo;
-                       }
-                       switch ( atom->getContentType() ) {
-                               case ObjectFile::Atom::kLazyPointer:
-                                       currentSectionInfo->fAllLazyPointers = true;
-                                       fSymbolTableCommands->needDynamicTable();
-                                       break;
-                               case ObjectFile::Atom::kNonLazyPointer:
-                                       currentSectionInfo->fAllNonLazyPointers = true;
-                                       fSymbolTableCommands->needDynamicTable();
-                                       break;
-                               case ObjectFile::Atom::kLazyDylibPointer:
-                                       currentSectionInfo->fAllLazyDylibPointers = true;
-                                       break;
-                               case ObjectFile::Atom::kStubHelper:
-                                       currentSectionInfo->fAllStubHelpers = true;
-                                       break;
-                               case ObjectFile::Atom::kCFIType:
-                                       currentSectionInfo->fAlignment = __builtin_ctz(sizeof(pint_t)); // always start CFI info pointer aligned
-                                       break;
-                               case ObjectFile::Atom::kStub:
-                                       if ( (strcmp(currentSectionInfo->fSegmentName, "__IMPORT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__jump_table") == 0) ) {
-                                               currentSectionInfo->fAllSelfModifyingStubs = true;
-                                               currentSectionInfo->fAlignment = 6; // force x86 fast stubs to start on 64-byte boundary
-                                       }
-                                       else {
-                                               currentSectionInfo->fAllStubs = true;
-                                       }
-                                       fSymbolTableCommands->needDynamicTable();
-                                       break;
-                               default:
-                                       break;
-                       }
-                       curSection = atom->getSection();
-               }
-               // any non-zero fill atoms make whole section marked not-zero-fill
-               if ( currentSectionInfo->fAllZeroFill && ! atom->isZeroFill() )
-                       currentSectionInfo->fAllZeroFill = false;
-               // change section object to be Writer's SectionInfo object
-               atom->setSection(currentSectionInfo);
-               // section alignment is that of a contained atom with the greatest alignment
-               uint8_t atomAlign = atom->getAlignment().powerOf2;
-               if ( currentSectionInfo->fAlignment < atomAlign ) 
-                       currentSectionInfo->fAlignment = atomAlign;
-               // calculate section offset for this atom
-               uint64_t offset = currentSectionInfo->fSize;
-               uint64_t alignment = 1 << atomAlign;
-               uint64_t currentModulus = (offset % alignment);
-               uint64_t requiredModulus = atom->getAlignment().modulus;
-               if ( currentModulus != requiredModulus ) {
-                       if ( requiredModulus > currentModulus )
-                               offset += requiredModulus-currentModulus;
-                       else
-                               offset += requiredModulus+alignment-currentModulus;             
-               }
-               atom->setSectionOffset(offset);
-               uint64_t curAtomSize = atom->getSize();
-               currentSectionInfo->fSize = offset + curAtomSize;
-               // add atom to section vector
-               currentSectionInfo->fAtoms.push_back(atom);
-               //fprintf(stderr, "  adding atom %p %s size=0x%0llX to section %p %s from %s\n", atom, atom->getDisplayName(), atom->getSize(),
-               //                              currentSectionInfo, currentSectionInfo->fSectionName, atom->getFile()->getPath());
-               // update largest size
-               if ( !currentSectionInfo->fAllZeroFill && (curAtomSize > fLargestAtomSize) )
-                       fLargestAtomSize = curAtomSize;
-       }
-       if ( (cstringSectionInfo != NULL) && (cstringSectionInfo->fAlignment > 0) ) {
-               // when merging cstring sections in .o files, all strings need to use the max alignment
-               uint64_t offset = 0;
-               uint64_t cstringAlignment = 1 << cstringSectionInfo->fAlignment;
-               for (std::vector<ObjectFile::Atom*>::iterator it=cstringSectionInfo->fAtoms.begin(); it != cstringSectionInfo->fAtoms.end(); it++) {
-                       offset = (offset + (cstringAlignment-1)) & (-cstringAlignment);
-                       ObjectFile::Atom* atom = *it;
-                       atom->setSectionOffset(offset);
-                       offset += atom->getSize();
-               }
-               cstringSectionInfo->fSize = offset;
-       }
-}
-
-
-struct TargetAndOffset { ObjectFile::Atom* atom; uint32_t offset; };
-class TargetAndOffsetComparor
-{
-public:
-       bool operator()(const TargetAndOffset& left, const TargetAndOffset& right) const
-       {
-               if ( left.atom != right.atom )
-                       return ( left.atom < right.atom );
-               return ( left.offset < right.offset );
-       }
-};
-
-template <>
-bool Writer<ppc>::addBranchIslands()
-{
-       return this->createBranchIslands();
-}
-
-template <>
-bool Writer<ppc64>::addBranchIslands()
-{
-       return this->createBranchIslands();
-}
-
-template <>
-bool Writer<x86>::addBranchIslands()
-{
-       // x86 branches can reach entire 4G address space, so no need for branch islands
-       return false;
-}
-
-template <>
-bool Writer<x86_64>::addBranchIslands()
-{
-       // x86 branches can reach entire 4G size of largest image
-       return false;
-}
-
-template <>
-bool Writer<arm>::addBranchIslands()
-{
-       return this->createBranchIslands();
-}
-
-template <>
-bool Writer<ppc>::isBranchThatMightNeedIsland(uint8_t kind)
-{
-       switch (kind) {
-               case ppc::kBranch24:
-               case ppc::kBranch24WeakImport:
-                       return true;
-       }
-       return false;
-}
-
-template <>
-bool Writer<ppc64>::isBranchThatMightNeedIsland(uint8_t kind)
-{
-       switch (kind) {
-               case ppc64::kBranch24:
-               case ppc64::kBranch24WeakImport:
-                       return true;
-       }
-       return false;
-}
-
-template <>
-bool Writer<arm>::isBranchThatMightNeedIsland(uint8_t kind)
-{
-       switch (kind) {
-               case arm::kBranch24:
-               case arm::kBranch24WeakImport:
-               case arm::kThumbBranch22:
-               case arm::kThumbBranch22WeakImport:
-                       return true;
-       }
-       return false;
-}
-
-template <> 
-uint32_t Writer<ppc>::textSizeWhenMightNeedBranchIslands() 
-{ 
-       return 16000000;
-}
-
-template <> 
-uint32_t Writer<ppc64>::textSizeWhenMightNeedBranchIslands() 
-{ 
-       return 16000000;
-}
-
-template <> 
-uint32_t Writer<arm>::textSizeWhenMightNeedBranchIslands() 
-{ 
-       if ( fHasThumbBranches == false )
-               return 32000000;  // ARM can branch +/- 32MB
-       else if ( fOptions.preferSubArchitecture() && fOptions.subArchitecture() == CPU_SUBTYPE_ARM_V7 ) 
-               return 16000000;  // thumb2 can branch +/- 16MB
-       else
-               return  4000000;  // thumb1 can branch +/- 4MB
-}
-
-template <> 
-uint32_t Writer<ppc>::maxDistanceBetweenIslands() 
-{ 
-       return 14*1024*1024;
-}
-
-template <> 
-uint32_t Writer<ppc64>::maxDistanceBetweenIslands() 
-{ 
-       return 14*1024*1024;
-}
-
-template <> 
-uint32_t Writer<arm>::maxDistanceBetweenIslands() 
-{ 
-       if ( fHasThumbBranches == false )
-               return 30*1024*1024;
-       else if ( fOptions.preferSubArchitecture() && fOptions.subArchitecture() == CPU_SUBTYPE_ARM_V7 ) 
-               return 14*1024*1024;
-       else
-               return 3500000; 
-}
-
-
-//
-// PowerPC can do PC relative branches as far as +/-16MB.
-// If a branch target is >16MB then we insert one or more
-// "branch islands" between the branch and its target that
-// allows island hopping to the target.
-//
-// Branch Island Algorithm
-//
-// If the __TEXT segment < 16MB, then no branch islands needed
-// Otherwise, every 14MB into the __TEXT segment a region is
-// added which can contain branch islands.  Every out-of-range
-// bl instruction is checked.  If it crosses a region, an island
-// is added to that region with the same target and the bl is
-// adjusted to target the island instead.
-//
-// In theory, if too many islands are added to one region, it
-// could grow the __TEXT enough that other previously in-range
-// bl branches could be pushed out of range.  We reduce the
-// probability this could happen by placing the ranges every
-// 14MB which means the region would have to be 2MB (512,000 islands)
-// before any branches could be pushed out of range.
-//
-template <typename A>
-bool Writer<A>::createBranchIslands()
-{
-       bool log = false;
-       bool result = false;
-       // Can only possibly need branch islands if __TEXT segment > 16M
-       if ( fLoadCommandsSegment->fSize > textSizeWhenMightNeedBranchIslands() ) {
-               if ( log) fprintf(stderr, "ld: checking for branch islands, __TEXT segment size=%llu\n", fLoadCommandsSegment->fSize);
-               const uint32_t kBetweenRegions = maxDistanceBetweenIslands(); // place regions of islands every 14MB in __text section
-               SectionInfo* textSection = NULL;
-               for (std::vector<SectionInfo*>::iterator it=fLoadCommandsSegment->fSections.begin(); it != fLoadCommandsSegment->fSections.end(); it++) {
-                       if ( strcmp((*it)->fSectionName, "__text") == 0 ) {
-                               textSection = *it;
-                               if ( log) fprintf(stderr, "ld: checking for branch islands, __text section size=%llu\n", textSection->fSize);
-                               break;
-                       }
-               }
-               const int kIslandRegionsCount = fLoadCommandsSegment->fSize / kBetweenRegions;
-               typedef std::map<TargetAndOffset,ObjectFile::Atom*, TargetAndOffsetComparor> AtomToIsland;
-               AtomToIsland regionsMap[kIslandRegionsCount];
-               std::vector<ObjectFile::Atom*> regionsIslands[kIslandRegionsCount];
-               unsigned int islandCount = 0;
-               if (log) fprintf(stderr, "ld: will use %u branch island regions\n", kIslandRegionsCount);
-
-               // create islands for branch references that are out of range
-               for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
-                       ObjectFile::Atom* atom = *it;
-                       std::vector<ObjectFile::Reference*>&  references = atom->getReferences();
-                       for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
-                               ObjectFile::Reference* ref = *rit;
-                               if ( this->isBranchThatMightNeedIsland(ref->getKind()) ) {
-                                       ObjectFile::Atom& target = ref->getTarget();
-                                       int64_t srcAddr = atom->getAddress() + ref->getFixUpOffset();
-                                       int64_t dstAddr = target.getAddress() + ref->getTargetOffset();
-                                       int64_t displacement = dstAddr - srcAddr;
-                                       TargetAndOffset finalTargetAndOffset = { &target, ref->getTargetOffset() };
-                                       const int64_t kBranchLimit = kBetweenRegions;
-                                       if ( displacement > kBranchLimit ) {
-                                               // create forward branch chain
-                                               ObjectFile::Atom* nextTarget = &target;
-                                               for (int i=kIslandRegionsCount-1; i >=0 ; --i) {
-                                                       AtomToIsland* region = &regionsMap[i];
-                                                       int64_t islandRegionAddr = kBetweenRegions * (i+1) + textSection->getBaseAddress();
-                                                       if ( (srcAddr < islandRegionAddr) && (islandRegionAddr <= dstAddr) ) { 
-                                                               AtomToIsland::iterator pos = region->find(finalTargetAndOffset);
-                                                               if ( pos == region->end() ) {
-                                                                       BranchIslandAtom<A>* island = new BranchIslandAtom<A>(*this, target.getDisplayName(), i, *nextTarget, *finalTargetAndOffset.atom, finalTargetAndOffset.offset);
-                                                                       island->setSection(textSection);
-                                                                       (*region)[finalTargetAndOffset] = island;
-                                                                       if (log) fprintf(stderr, "added island %s to region %d for %s\n", island->getDisplayName(), i, atom->getDisplayName());
-                                                                       regionsIslands[i].push_back(island);
-                                                                       ++islandCount;
-                                                                       nextTarget = island;
-                                                               }
-                                                               else {
-                                                                       nextTarget = pos->second;
-                                                               }
-                                                       }
-                                               }
-                                               if (log) fprintf(stderr, "using island %s for branch to %s from %s\n", nextTarget->getDisplayName(), target.getDisplayName(), atom->getDisplayName());
-                                               ref->setTarget(*nextTarget, 0);
-                                       }
-                                       else if ( displacement < (-kBranchLimit) ) {
-                                               // create back branching chain
-                                               ObjectFile::Atom* prevTarget = &target;
-                                               for (int i=0; i < kIslandRegionsCount ; ++i) {
-                                                       AtomToIsland* region = &regionsMap[i];
-                                                       int64_t islandRegionAddr = kBetweenRegions * (i+1);
-                                                       if ( (dstAddr <= islandRegionAddr) && (islandRegionAddr < srcAddr) ) {
-                                                               AtomToIsland::iterator pos = region->find(finalTargetAndOffset);
-                                                               if ( pos == region->end() ) {
-                                                                       BranchIslandAtom<A>* island = new BranchIslandAtom<A>(*this, target.getDisplayName(), i, *prevTarget, *finalTargetAndOffset.atom, finalTargetAndOffset.offset);
-                                                                       island->setSection(textSection);
-                                                                       (*region)[finalTargetAndOffset] = island;
-                                                                       if (log) fprintf(stderr, "added back island %s to region %d for %s\n", island->getDisplayName(), i, atom->getDisplayName());
-                                                                       regionsIslands[i].push_back(island);
-                                                                       ++islandCount;
-                                                                       prevTarget = island;
-                                                               }
-                                                               else {
-                                                                       prevTarget = pos->second;
-                                                               }
-                                                       }
-                                               }
-                                               if (log) fprintf(stderr, "using back island %s for %s\n", prevTarget->getDisplayName(), atom->getDisplayName());
-                                               ref->setTarget(*prevTarget, 0);
-                                       }
-                               }
-                       }
-               }
-
-               // insert islands into __text section and adjust section offsets
-               if ( islandCount > 0 ) {
-                       if ( log ) fprintf(stderr, "ld: %u branch islands required in %u regions\n", islandCount, kIslandRegionsCount);
-                       std::vector<ObjectFile::Atom*> newAtomList;
-                       newAtomList.reserve(textSection->fAtoms.size()+islandCount);
-                       uint64_t islandRegionAddr = kBetweenRegions + textSection->getBaseAddress();
-                       uint64_t textSectionAlignment = (1 << textSection->fAlignment);
-                       int regionIndex = 0;
-                       uint64_t atomSlide = 0;
-                       uint64_t sectionOffset = 0;
-                       for (std::vector<ObjectFile::Atom*>::iterator it=textSection->fAtoms.begin(); it != textSection->fAtoms.end(); it++) {
-                               ObjectFile::Atom* atom = *it;
-                               if ( (atom->getAddress()+atom->getSize()) > islandRegionAddr ) {
-                                       uint64_t islandStartOffset = atom->getSectionOffset() + atomSlide;
-                                       sectionOffset = islandStartOffset;
-                                       std::vector<ObjectFile::Atom*>* regionIslands = &regionsIslands[regionIndex];
-                                       for (std::vector<ObjectFile::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
-                                               ObjectFile::Atom* islandAtom = *rit;
-                                               newAtomList.push_back(islandAtom);
-                                               uint64_t alignment = 1 << (islandAtom->getAlignment().powerOf2);
-                                               sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
-                                               islandAtom->setSectionOffset(sectionOffset);
-                                               if ( log ) fprintf(stderr, "assigning  __text offset 0x%08llx to %s\n", sectionOffset, islandAtom->getDisplayName());
-                                               sectionOffset += islandAtom->getSize();
-                                       }
-                                       ++regionIndex;
-                                       islandRegionAddr += kBetweenRegions;
-                                       uint64_t islandRegionAlignmentBlocks = (sectionOffset - islandStartOffset + textSectionAlignment - 1) / textSectionAlignment;
-                                       atomSlide += (islandRegionAlignmentBlocks * textSectionAlignment);
-                               }
-                               newAtomList.push_back(atom);
-                               if ( atomSlide != 0 )
-                                       atom->setSectionOffset(atom->getSectionOffset()+atomSlide);
-                       }
-                       sectionOffset = textSection->fSize+atomSlide;
-                       // put any remaining islands at end of __text section
-                       if ( regionIndex < kIslandRegionsCount ) {
-                               std::vector<ObjectFile::Atom*>* regionIslands = &regionsIslands[regionIndex];
-                               for (std::vector<ObjectFile::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
-                                       ObjectFile::Atom* islandAtom = *rit;
-                                       newAtomList.push_back(islandAtom);
-                                       uint64_t alignment = 1 << (islandAtom->getAlignment().powerOf2);
-                                       sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
-                                       islandAtom->setSectionOffset(sectionOffset);
-                                       if ( log ) fprintf(stderr, "assigning  __text offset 0x%08llx to %s\n", sectionOffset, islandAtom->getDisplayName());
-                                       sectionOffset += islandAtom->getSize();
-                               }
-                       }
-
-                       textSection->fAtoms = newAtomList;
-                       textSection->fSize = sectionOffset;
-                       result = true;
-               }
-
-       }
-       return result;
-}
-
-
-template <typename A>
-void Writer<A>::adjustLoadCommandsAndPadding()
-{
-       fSegmentCommands->computeSize();
-
-       // recompute load command section offsets
-       uint64_t offset = 0;
-       std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fLoadCommandsSection->fAtoms;
-       const unsigned int atomCount = loadCommandAtoms.size();
-       for (unsigned int i=0; i < atomCount; ++i) {
-               ObjectFile::Atom* atom = loadCommandAtoms[i];
-               uint64_t alignment = 1 << atom->getAlignment().powerOf2;
-               offset = ( (offset+alignment-1) & (-alignment) );
-               atom->setSectionOffset(offset);
-               uint32_t atomSize = atom->getSize();
-               if ( atomSize > fLargestAtomSize )
-                       fLargestAtomSize = atomSize;
-               offset += atomSize;
-               fLoadCommandsSection->fSize = offset;
-       }
-       const uint32_t sizeOfLoadCommandsPlusHeader = offset + sizeof(macho_header<typename A::P>);
-
-       std::vector<SectionInfo*>& sectionInfos = fLoadCommandsSegment->fSections;
-       const int sectionCount = sectionInfos.size();
-       uint32_t totalSizeOfTEXTLessHeaderAndLoadCommands = 0;
-       for(int j=0; j < sectionCount; ++j) {
-               SectionInfo* curSection = sectionInfos[j];
-               if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
-                       break;
-               totalSizeOfTEXTLessHeaderAndLoadCommands += curSection->fSize;
-       }
-       uint64_t paddingSize = 0;
-       if ( fOptions.outputKind() == Options::kDyld ) {
-               // dyld itself has special padding requirements.  We want the beginning __text section to start at a stable address
-               paddingSize = 4096 - (totalSizeOfTEXTLessHeaderAndLoadCommands % 4096);
-       }
-       else if ( fOptions.outputKind() == Options::kObjectFile ) {
-               // mach-o .o files need no padding between load commands and first section
-               // but leave enough room that the object file could be signed
-               paddingSize = 32;
-       }
-       else if ( fOptions.outputKind() == Options::kPreload ) {
-               // mach-o MH_PRELOAD files need no padding between load commands and first section
-               paddingSize = 0;
-       }
-       else {
-               // work backwards from end of segment and lay out sections so that extra room goes to padding atom
-               uint64_t addr = 0;
-               for(int j=sectionCount-1; j >=0; --j) {
-                       SectionInfo* curSection = sectionInfos[j];
-                       if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 ) {
-                               addr -= (fLoadCommandsSection->fSize+fMachHeaderAtom->getSize());
-                               paddingSize = addr % fOptions.segmentAlignment();
-                               break;
-                       }
-                       addr -= curSection->fSize;
-                       addr = addr & (0 - (1 << curSection->fAlignment));
-               }
-
-               // if command line requires more padding than this
-               uint32_t minPad = fOptions.minimumHeaderPad();
-               if ( fOptions.maxMminimumHeaderPad() ) {
-                       // -headerpad_max_install_names means there should be room for every path load command to grow to 1204 bytes
-                       uint32_t altMin = fLibraryToOrdinal.size() * MAXPATHLEN;
-                       if ( fOptions.outputKind() ==  Options::kDynamicLibrary )
-                               altMin += MAXPATHLEN;
-                       if ( altMin > minPad )
-                               minPad = altMin;
-               }
-               if ( paddingSize < minPad ) {
-                       int extraPages = (minPad - paddingSize + fOptions.segmentAlignment() - 1)/fOptions.segmentAlignment();
-                       paddingSize += extraPages * fOptions.segmentAlignment();
-               }
-               
-               if ( fOptions.makeEncryptable() ) {
-                       // load commands must be on a separate non-encrypted page
-                       int loadCommandsPage = (sizeOfLoadCommandsPlusHeader + minPad)/fOptions.segmentAlignment();
-                       int textPage = (sizeOfLoadCommandsPlusHeader + paddingSize)/fOptions.segmentAlignment();
-                       if ( loadCommandsPage == textPage ) {
-                               paddingSize += fOptions.segmentAlignment();
-                               textPage += 1;
-                       }
-                       
-                       //paddingSize = 4096 - ((totalSizeOfTEXTLessHeaderAndLoadCommands+fOptions.minimumHeaderPad()) % 4096) + fOptions.minimumHeaderPad();
-                       fEncryptionLoadCommand->setStartEncryptionOffset(textPage*fOptions.segmentAlignment());
-               }
-       }
-
-       // adjust atom size and update section size
-       fHeaderPadding->setSize(paddingSize);
-       for(int j=0; j < sectionCount; ++j) {
-               SectionInfo* curSection = sectionInfos[j];
-               if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
-                       curSection->fSize = paddingSize;
-       }
-}
-
-static uint64_t segmentAlign(uint64_t addr, uint64_t alignment) 
-{ 
-       return ((addr+alignment-1) & (-alignment)); 
-}
-
-// assign file offsets and logical address to all segments
-template <typename A>
-void Writer<A>::assignFileOffsets()
-{
-       const bool virtualSectionOccupyAddressSpace = ((fOptions.outputKind() != Options::kObjectFile)
-                                                                                               && (fOptions.outputKind() != Options::kPreload));
-       bool haveFixedSegments = false;
-       uint64_t fileOffset = 0;
-       uint64_t nextContiguousAddress = fOptions.baseAddress();
-       uint64_t nextReadOnlyAddress = fOptions.baseAddress();
-       uint64_t nextWritableAddress = fOptions.baseWritableAddress();
-
-       // process segments with fixed addresses (-segaddr)
-       for (std::vector<Options::SegmentStart>::iterator it = fOptions.customSegmentAddresses().begin(); it != fOptions.customSegmentAddresses().end(); ++it) {
-                       for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
-                       SegmentInfo* curSegment = *segit;
-                       if ( strcmp(curSegment->fName, it->name) == 0 ) {
-                               curSegment->fBaseAddress = it->address;
-                               curSegment->fFixedAddress = true;
-                               break;
-                       }
-               }
-       }
-
-       // process segments with fixed addresses (-seg_page_size)
-       for (std::vector<Options::SegmentSize>::iterator it = fOptions.customSegmentSizes().begin(); it != fOptions.customSegmentSizes().end(); ++it) {
-                       for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
-                       SegmentInfo* curSegment = *segit;
-                       if ( strcmp(curSegment->fName, it->name) == 0 ) {
-                               curSegment->fPageSize = it->size;
-                               break;
-                       }
-               }
-       }
-
-       // Run through the segments and each segment's sections to assign addresses
-       for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
-               SegmentInfo* curSegment = *segit;
-               
-               if ( fOptions.splitSeg() ) {
-                       if ( curSegment->fInitProtection & VM_PROT_WRITE ) 
-                               nextContiguousAddress = nextWritableAddress;
-                       else
-                               nextContiguousAddress = nextReadOnlyAddress;
-               }
-               
-               if ( fOptions.outputKind() == Options::kPreload ) {
-                       if ( strcmp(curSegment->fName, "__HEADER") == 0 ) 
-                               nextContiguousAddress = 0;
-                       else if ( strcmp(curSegment->fName, "__TEXT") == 0 ) 
-                               nextContiguousAddress = fOptions.baseAddress();
-               }
-
-               fileOffset = segmentAlign(fileOffset, curSegment->fPageSize);
-               curSegment->fFileOffset = fileOffset;
-               
-               // Set the segment base address
-               if ( curSegment->fFixedAddress )
-                       haveFixedSegments = true;
-               else
-                       curSegment->fBaseAddress = segmentAlign(nextContiguousAddress, curSegment->fPageSize);
-
-               // We've set the segment address, now run through each section.
-               uint64_t address = curSegment->fBaseAddress;
-               SectionInfo* firstZeroFillSection = NULL;
-               SectionInfo* prevSection = NULL;
-               
-               std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
-               
-               for (std::vector<SectionInfo*>::iterator it = sectionInfos.begin(); it != sectionInfos.end(); ++it) {
-                       SectionInfo* curSection = *it;
-               
-                       // adjust section address based on alignment
-                       uint64_t alignment = 1 << curSection->fAlignment;
-                       if ( curSection->fAtoms.size() == 1 ) {
-                               // if there is only one atom in section, use modulus for even better layout
-                               ObjectFile::Alignment atomAlign = curSection->fAtoms[0]->getAlignment();
-                               uint64_t atomAlignP2 = (1 << atomAlign.powerOf2);
-                               uint64_t currentModulus = (address % atomAlignP2);
-                               if ( currentModulus != atomAlign.modulus ) {
-                                       if ( atomAlign.modulus > currentModulus )
-                                               address += atomAlign.modulus-currentModulus;
-                                       else
-                                               address += atomAlign.modulus+atomAlignP2-currentModulus;                
-                               }
-                       }
-                       else {
-                               address = ( (address+alignment-1) & (-alignment) );
-                       }
-                       // adjust file offset to match address
-                       if ( prevSection != NULL ) {
-                               if ( virtualSectionOccupyAddressSpace || !prevSection->fVirtualSection )
-                                       fileOffset = (address - prevSection->getBaseAddress()) + prevSection->fFileOffset;
-                               else
-                                       fileOffset = ( (fileOffset+alignment-1) & (-alignment) );
-                       }
-                       
-                       // update section info
-                       curSection->fFileOffset = fileOffset;
-                       curSection->setBaseAddress(address);
-                       //fprintf(stderr, "%s %s addr=0x%llX, fileoffset=0x%llX, size=0x%llX\n", curSegment->fName, curSection->fSectionName, address, fileOffset, curSection->fSize);
-
-                       // keep track of trailing zero fill sections
-                       if ( curSection->fAllZeroFill && (firstZeroFillSection == NULL) )
-                               firstZeroFillSection = curSection;
-                       if ( !curSection->fAllZeroFill && (firstZeroFillSection != NULL) && (fOptions.outputKind() != Options::kObjectFile) ) 
-                               throwf("zero-fill section %s not at end of segment", curSection->fSectionName);
-                       
-                       // update running pointers
-                       if ( virtualSectionOccupyAddressSpace || !curSection->fVirtualSection )
-                               address += curSection->fSize;
-                       fileOffset += curSection->fSize;
-                       
-                       // sanity check size of 32-bit binaries
-                       if ( address > maxAddress() )
-                               throwf("section %s exceeds 4GB limit", curSection->fSectionName);
-                       
-                       // update segment info
-                       curSegment->fFileSize = fileOffset - curSegment->fFileOffset;
-                       curSegment->fSize = curSegment->fFileSize;
-                       prevSection = curSection;
-               }
-               
-               if ( fOptions.outputKind() == Options::kObjectFile ) {
-                       // don't page align .o files
-               }
-               else {
-                       // optimize trailing zero-fill sections to not occupy disk space
-                       if ( firstZeroFillSection != NULL ) {
-                               curSegment->fFileSize = firstZeroFillSection->fFileOffset - curSegment->fFileOffset;
-                               fileOffset = firstZeroFillSection->fFileOffset;
-                       }
-                       // page align segment size
-                       curSegment->fFileSize = segmentAlign(curSegment->fFileSize, curSegment->fPageSize);
-                       curSegment->fSize         = segmentAlign(curSegment->fSize, curSegment->fPageSize);
-                       if ( !curSegment->fIndependentAddress && (curSegment->fBaseAddress >= nextContiguousAddress) ) {
-                               nextContiguousAddress = segmentAlign(curSegment->fBaseAddress+curSegment->fSize, curSegment->fPageSize);
-                               fileOffset = segmentAlign(fileOffset, curSegment->fPageSize);
-                               if ( curSegment->fInitProtection & VM_PROT_WRITE )
-                                       nextWritableAddress = nextContiguousAddress;
-                               else
-                                       nextReadOnlyAddress = nextContiguousAddress;
-                       }
-               }
-               //fprintf(stderr, "end of seg %s, fileoffset=0x%llX, nextContiguousAddress=0x%llX\n", curSegment->fName, fileOffset, nextContiguousAddress);
-       }
-                       
-       // check for segment overlaps caused by user specified fixed segments (e.g. __PAGEZERO, __UNIXSTACK)
-       if ( haveFixedSegments ) {
-               int segCount = fSegmentInfos.size();
-               for(int i=0; i < segCount; ++i) {
-                       SegmentInfo* segment1 = fSegmentInfos[i];
-                       
-                       for(int j=0; j < segCount; ++j) {
-                               if ( i != j ) {
-                                       SegmentInfo* segment2 = fSegmentInfos[j];
-                                       
-                                       if ( segment1->fBaseAddress < segment2->fBaseAddress ) {
-                                               if ( (segment1->fBaseAddress+segment1->fSize) > segment2->fBaseAddress )
-                                                       throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
-                                                               segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
-                                       }
-                                       else if ( segment1->fBaseAddress > segment2->fBaseAddress ) {
-                                               if ( (segment2->fBaseAddress+segment2->fSize) > segment1->fBaseAddress )
-                                                       throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
-                                                               segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
-                                       }
-                                       else if ( (segment1->fSize != 0) && (segment2->fSize != 0) ) {
-                                                       throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
-                                                               segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
-                                       }
-                               }
-                       }
-               }
-       }
-
-       // set up fFirstWritableSegment and fWritableSegmentPastFirst4GB
-       for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
-               SegmentInfo* curSegment = *segit;
-               if ( (curSegment->fInitProtection & VM_PROT_WRITE) != 0 ) {
-                       if ( fFirstWritableSegment == NULL )
-                               fFirstWritableSegment = curSegment;
-                       if ( (curSegment->fBaseAddress + curSegment->fSize - fOptions.baseAddress()) >= 0x100000000LL )
-                               fWritableSegmentPastFirst4GB = true;
-               }
-       }
-       
-       // record size of encrypted part of __TEXT segment
-       if ( fOptions.makeEncryptable() ) {
-               for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
-                       SegmentInfo* curSegment = *segit;
-                       if ( strcmp(curSegment->fName, "__TEXT") == 0 ) {
-                               fEncryptionLoadCommand->setEndEncryptionOffset(curSegment->fFileSize);
-                               break;
-                       }
-               }
-       }
-
-}
-
-template <typename A>
-void Writer<A>::adjustLinkEditSections()
-{
-       // link edit content is always in last segment
-       SegmentInfo* lastSeg = fSegmentInfos[fSegmentInfos.size()-1];
-       unsigned int firstLinkEditSectionIndex = 0;
-       while ( strcmp(lastSeg->fSections[firstLinkEditSectionIndex]->fSegmentName, "__LINKEDIT") != 0 )
-               ++firstLinkEditSectionIndex;
-
-       const unsigned int linkEditSectionCount = lastSeg->fSections.size();
-       uint64_t fileOffset = lastSeg->fSections[firstLinkEditSectionIndex]->fFileOffset;
-       uint64_t address = lastSeg->fSections[firstLinkEditSectionIndex]->getBaseAddress();
-       if ( fPadSegmentInfo != NULL ) {
-               // insert __4GBFILL segment into segments vector before LINKEDIT
-               for(std::vector<SegmentInfo*>::iterator it = fSegmentInfos.begin(); it != fSegmentInfos.end(); ++it) {
-                       if ( *it == lastSeg ) {
-                               fSegmentInfos.insert(it, fPadSegmentInfo);
-                               break;
-                       }
-               }
-               // adjust  __4GBFILL segment to span from end of last segment to zeroPageSize
-               fPadSegmentInfo->fSize = fOptions.zeroPageSize() - address;
-               fPadSegmentInfo->fBaseAddress = address;
-               // adjust LINKEDIT to start at zeroPageSize
-               address = fOptions.zeroPageSize();
-               lastSeg->fBaseAddress = fOptions.zeroPageSize();
-       }
-       for (unsigned int i=firstLinkEditSectionIndex; i < linkEditSectionCount; ++i) {
-               std::vector<class ObjectFile::Atom*>& atoms = lastSeg->fSections[i]->fAtoms;
-               // adjust section address based on alignment
-               uint64_t sectionAlignment = 1 << lastSeg->fSections[i]->fAlignment;
-               uint64_t pad = ((address+sectionAlignment-1) & (-sectionAlignment)) - address;
-               address += pad;
-               fileOffset += pad;      // adjust file offset to match address
-               lastSeg->fSections[i]->setBaseAddress(address);
-               if ( strcmp(lastSeg->fSections[i]->fSectionName, "._absolute") == 0 )
-                       lastSeg->fSections[i]->setBaseAddress(0);
-               lastSeg->fSections[i]->fFileOffset = fileOffset;
-               uint64_t sectionOffset = 0;
-               for (unsigned int j=0; j < atoms.size(); ++j) {
-                       ObjectFile::Atom* atom = atoms[j];
-                       uint64_t alignment = 1 << atom->getAlignment().powerOf2;
-                       sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
-                       atom->setSectionOffset(sectionOffset);
-                       uint64_t size = atom->getSize();
-                       sectionOffset += size;
-                       if ( size > fLargestAtomSize )
-                               fLargestAtomSize = size;
-               }
-               //fprintf(stderr, "setting: lastSeg->fSections[%d]->fSize = 0x%08llX\n", i, sectionOffset);
-               lastSeg->fSections[i]->fSize = sectionOffset;
-               fileOffset += sectionOffset;
-               address += sectionOffset;
-       }
-       if ( fOptions.outputKind() == Options::kObjectFile ) {
-               //lastSeg->fBaseAddress = 0;
-               //lastSeg->fSize = lastSeg->fSections[firstLinkEditSectionIndex]->
-               //lastSeg->fFileOffset = 0;
-               //lastSeg->fFileSize =
-       }
-       else {
-               lastSeg->fFileSize = fileOffset - lastSeg->fFileOffset;
-               lastSeg->fSize     = (address - lastSeg->fBaseAddress+4095) & (-4096);
-       }
-}
-
-
-template <typename A>
-ObjectFile::Atom::Scope MachHeaderAtom<A>::getScope() const
-{
-       switch ( fWriter.fOptions.outputKind() ) {
-               case Options::kDynamicExecutable:
-               case Options::kStaticExecutable:
-                       return ObjectFile::Atom::scopeGlobal;
-               case Options::kDynamicLibrary:
-               case Options::kDynamicBundle:
-               case Options::kDyld:
-               case Options::kObjectFile:
-               case Options::kPreload:
-               case Options::kKextBundle:
-                       return ObjectFile::Atom::scopeLinkageUnit;
-       }
-       throw "unknown header type";
-}
-
-template <typename A>
-ObjectFile::Atom::SymbolTableInclusion MachHeaderAtom<A>::getSymbolTableInclusion() const
-{
-       switch ( fWriter.fOptions.outputKind() ) {
-               case Options::kDynamicExecutable:
-                       return ObjectFile::Atom::kSymbolTableInAndNeverStrip;
-               case Options::kStaticExecutable:
-                       return ObjectFile::Atom::kSymbolTableInAsAbsolute;
-               case Options::kDynamicLibrary:
-               case Options::kDynamicBundle:
-               case Options::kDyld:
-                       return ObjectFile::Atom::kSymbolTableIn;
-               case Options::kObjectFile:
-               case Options::kPreload:
-               case Options::kKextBundle:
-                       return ObjectFile::Atom::kSymbolTableNotIn;
-       }
-       throw "unknown header type";
-}
-
-template <typename A>
-const char* MachHeaderAtom<A>::getName() const
-{
-       switch ( fWriter.fOptions.outputKind() ) {
-               case Options::kDynamicExecutable:
-               case Options::kStaticExecutable:
-                       return "__mh_execute_header";
-               case Options::kDynamicLibrary:
-                       return "__mh_dylib_header";
-               case Options::kDynamicBundle:
-                       return "__mh_bundle_header";
-               case Options::kObjectFile:
-               case Options::kPreload:
-               case Options::kKextBundle:
-                       return NULL;
-               case Options::kDyld:
-                       return "__mh_dylinker_header";
-       }
-       throw "unknown header type";
-}
-
-template <typename A>
-const char* MachHeaderAtom<A>::getDisplayName() const
-{
-       switch ( fWriter.fOptions.outputKind() ) {
-               case Options::kDynamicExecutable:
-               case Options::kStaticExecutable:
-               case Options::kDynamicLibrary:
-               case Options::kDynamicBundle:
-               case Options::kDyld:
-                       return this->getName();
-               case Options::kObjectFile:
-               case Options::kPreload:
-               case Options::kKextBundle:
-                       return "mach header";
-       }
-       throw "unknown header type";
-}
-
-template <typename A>
-void MachHeaderAtom<A>::copyRawContent(uint8_t buffer[]) const
-{
-       // get file type
-       uint32_t fileType = 0;
-       switch ( fWriter.fOptions.outputKind() ) {
-               case Options::kDynamicExecutable:
-               case Options::kStaticExecutable:
-                       fileType = MH_EXECUTE;
-                       break;
-               case Options::kDynamicLibrary:
-                       fileType = MH_DYLIB;
-                       break;
-               case Options::kDynamicBundle:
-                       fileType = MH_BUNDLE;
-                       break;
-               case Options::kObjectFile:
-                       fileType = MH_OBJECT;
-                       break;
-               case Options::kDyld:
-                       fileType = MH_DYLINKER;
-                       break;
-               case Options::kPreload:
-                       fileType = MH_PRELOAD;
-                       break;
-               case Options::kKextBundle:
-                       fileType = MH_KEXT_BUNDLE;
-                       break;
-       }
-
-       // get flags
-       uint32_t flags = 0;
-       if ( fWriter.fOptions.outputKind() == Options::kObjectFile ) {
-               if ( fWriter.fCanScatter )
-                       flags = MH_SUBSECTIONS_VIA_SYMBOLS;
-       }
-       else {
-               if ( fWriter.fOptions.outputKind() == Options::kStaticExecutable ) {
-                       flags |= MH_NOUNDEFS;
-               }
-               else if ( fWriter.fOptions.outputKind() == Options::kPreload ) {
-                       flags |= MH_NOUNDEFS;
-                       if ( fWriter.fOptions.positionIndependentExecutable() ) 
-                               flags |= MH_PIE;
-               }
-               else {
-                       flags = MH_DYLDLINK;
-                       if ( fWriter.fOptions.bindAtLoad() )
-                               flags |= MH_BINDATLOAD;
-                       switch ( fWriter.fOptions.nameSpace() ) {
-                               case Options::kTwoLevelNameSpace:
-                                       flags |= MH_TWOLEVEL | MH_NOUNDEFS;
-                                       break;
-                               case Options::kFlatNameSpace:
-                                       break;
-                               case Options::kForceFlatNameSpace:
-                                       flags |= MH_FORCE_FLAT;
-                                       break;
-                       }
-                       bool hasWeakDefines = fWriter.fHasWeakExports;
-                       if ( fWriter.fRegularDefAtomsThatOverrideADylibsWeakDef->size() != 0 ) {
-                               for(std::set<const ObjectFile::Atom*>::iterator it = fWriter.fRegularDefAtomsThatOverrideADylibsWeakDef->begin();
-                                                                                                       it != fWriter.fRegularDefAtomsThatOverrideADylibsWeakDef->end(); ++it) {
-                                       if ( fWriter.shouldExport(**it) ) {
-                                               hasWeakDefines = true;
-                                               break;
-                                       }
-                               }
-                       }
-                       if ( hasWeakDefines )
-                               flags |= MH_WEAK_DEFINES;
-                       if ( fWriter.fReferencesWeakImports || fWriter.fHasWeakExports )
-                               flags |= MH_BINDS_TO_WEAK;
-                       if ( fWriter.fOptions.prebind() )
-                               flags |= MH_PREBOUND;
-                       if ( fWriter.fOptions.splitSeg() )
-                               flags |= MH_SPLIT_SEGS;
-                       if ( (fWriter.fOptions.outputKind() == Options::kDynamicLibrary) && fWriter.fNoReExportedDylibs ) 
-                               flags |= MH_NO_REEXPORTED_DYLIBS;
-                       if ( fWriter.fOptions.positionIndependentExecutable() ) 
-                               flags |= MH_PIE;
-                       if ( fWriter.fOptions.markAutoDeadStripDylib() ) 
-                               flags |= MH_DEAD_STRIPPABLE_DYLIB;
-               }
-               if ( fWriter.fOptions.hasExecutableStack() )
-                       flags |= MH_ALLOW_STACK_EXECUTION;
-               if ( fWriter.fOptions.readerOptions().fRootSafe )
-                       flags |= MH_ROOT_SAFE;
-               if ( fWriter.fOptions.readerOptions().fSetuidSafe )
-                       flags |= MH_SETUID_SAFE;
-       }
-
-       // get commands info
-       uint32_t commandsSize = 0;
-       uint32_t commandsCount = 0;
-
-       std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fWriter.fLoadCommandsSection->fAtoms;
-       for (std::vector<ObjectFile::Atom*>::iterator it=loadCommandAtoms.begin(); it != loadCommandAtoms.end(); it++) {
-               ObjectFile::Atom* atom = *it;
-               commandsSize += atom->getSize();
-               // segment and symbol table atoms can contain more than one load command
-               if ( atom == fWriter.fSegmentCommands )
-                       commandsCount += fWriter.fSegmentCommands->commandCount();
-               else if ( atom == fWriter.fSymbolTableCommands )
-                       commandsCount += fWriter.fSymbolTableCommands->commandCount();
-               else if ( atom->getSize() != 0 )
-                       ++commandsCount;
-       }
-
-       // fill out mach_header
-       macho_header<typename A::P>* mh = (macho_header<typename A::P>*)buffer;
-       setHeaderInfo(*mh);
-       mh->set_filetype(fileType);
-       mh->set_ncmds(commandsCount);
-       mh->set_sizeofcmds(commandsSize);
-       mh->set_flags(flags);
-}
-
-template <>
-void MachHeaderAtom<ppc>::setHeaderInfo(macho_header<ppc::P>& header) const
-{
-       header.set_magic(MH_MAGIC);
-       header.set_cputype(CPU_TYPE_POWERPC);
-    header.set_cpusubtype(fWriter.fCpuConstraint);
-}
-
-template <>
-void MachHeaderAtom<ppc64>::setHeaderInfo(macho_header<ppc64::P>& header) const
-{
-       header.set_magic(MH_MAGIC_64);
-       header.set_cputype(CPU_TYPE_POWERPC64);
-       if ( (fWriter.fOptions.outputKind() == Options::kDynamicExecutable) && (fWriter.fOptions.macosxVersionMin() >= ObjectFile::ReaderOptions::k10_5) )
-               header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL | 0x80000000);
-       else
-               header.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL);
-       header.set_reserved(0);
-}
-
-template <>
-void MachHeaderAtom<x86>::setHeaderInfo(macho_header<x86::P>& header) const
-{
-       header.set_magic(MH_MAGIC);
-       header.set_cputype(CPU_TYPE_I386);
-       header.set_cpusubtype(CPU_SUBTYPE_I386_ALL);
-}
-
-template <>
-void MachHeaderAtom<x86_64>::setHeaderInfo(macho_header<x86_64::P>& header) const
-{
-       header.set_magic(MH_MAGIC_64);
-       header.set_cputype(CPU_TYPE_X86_64);
-       if ( (fWriter.fOptions.outputKind() == Options::kDynamicExecutable) && (fWriter.fOptions.macosxVersionMin() >= ObjectFile::ReaderOptions::k10_5) )
-               header.set_cpusubtype(CPU_SUBTYPE_X86_64_ALL | 0x80000000);
-       else
-               header.set_cpusubtype(CPU_SUBTYPE_X86_64_ALL);
-       header.set_reserved(0);
-}
-
-template <>
-void MachHeaderAtom<arm>::setHeaderInfo(macho_header<arm::P>& header) const
-{
-       header.set_magic(MH_MAGIC);
-       header.set_cputype(CPU_TYPE_ARM);
-       header.set_cpusubtype(fWriter.fCpuConstraint);
-}
-
-template <typename A>
-CustomStackAtom<A>::CustomStackAtom(Writer<A>& writer)
- : WriterAtom<A>(writer, Segment::fgStackSegment)
-{
-       if ( stackGrowsDown() )
-               Segment::fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr() - writer.fOptions.customStackSize());
-       else
-               Segment::fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr());
-}
-
-
-template <> bool CustomStackAtom<ppc>::stackGrowsDown()    { return true; }
-template <> bool CustomStackAtom<ppc64>::stackGrowsDown()  { return true; }
-template <> bool CustomStackAtom<x86>::stackGrowsDown()    { return true; }
-template <> bool CustomStackAtom<x86_64>::stackGrowsDown() { return true; }
-template <> bool CustomStackAtom<arm>::stackGrowsDown()    { return true; }
-
-template <typename A>
-void SegmentLoadCommandsAtom<A>::computeSize()
-{
-       uint64_t size = 0;
-       std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
-       int segCount = 0;
-       for(std::vector<SegmentInfo*>::iterator it = segmentInfos.begin(); it != segmentInfos.end(); ++it) {
-               SegmentInfo* seg = *it;
-               if ( seg->fHasLoadCommand ) {
-                       ++segCount;
-                       size += sizeof(macho_segment_command<P>);
-                       std::vector<SectionInfo*>& sectionInfos = seg->fSections;
-                       const int sectionCount = sectionInfos.size();
-                       for(int j=0; j < sectionCount; ++j) {
-                               if ( fWriter.fEmitVirtualSections || ! sectionInfos[j]->fVirtualSection )
-                                       size += sizeof(macho_section<P>);
-                       }
-               }
-       }
-       fSize = size;
-       fCommandCount = segCount;
-       if ( fWriter.fPadSegmentInfo != NULL ) {
-               ++fCommandCount;
-               fSize += sizeof(macho_segment_command<P>);
-       }
-}
-
-template <>
-uint64_t LoadCommandAtom<ppc>::alignedSize(uint64_t size)
-{
-       return ((size+3) & (-4));       // 4-byte align all load commands for 32-bit mach-o
-}
-
-template <>
-uint64_t LoadCommandAtom<ppc64>::alignedSize(uint64_t size)
-{
-       return ((size+7) & (-8));       // 8-byte align all load commands for 64-bit mach-o
-}
-
-template <>
-uint64_t LoadCommandAtom<x86>::alignedSize(uint64_t size)
-{
-       return ((size+3) & (-4));       // 4-byte align all load commands for 32-bit mach-o
-}
-
-template <>
-uint64_t LoadCommandAtom<x86_64>::alignedSize(uint64_t size)
-{
-       return ((size+7) & (-8));       // 8-byte align all load commands for 64-bit mach-o
-}
-
-template <>
-uint64_t LoadCommandAtom<arm>::alignedSize(uint64_t size)
-{
-       return ((size+3) & (-4));       // 4-byte align all load commands for 32-bit mach-o
-}
-
-template <typename A>
-void SegmentLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
-{
-       uint64_t size = this->getSize();
-       const bool oneSegment =( fWriter.fOptions.outputKind() == Options::kObjectFile );
-       bzero(buffer, size);
-       uint8_t* p = buffer;
-       typename std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
-       for(std::vector<SegmentInfo*>::iterator it = segmentInfos.begin(); it != segmentInfos.end(); ++it) {
-               SegmentInfo* segInfo = *it;
-               if ( ! segInfo->fHasLoadCommand )
-                       continue;
-               const int sectionCount = segInfo->fSections.size();
-               macho_segment_command<P>* cmd = (macho_segment_command<P>*)p;
-               cmd->set_cmd(macho_segment_command<P>::CMD);
-               cmd->set_segname(segInfo->fName);
-               cmd->set_vmaddr(segInfo->fBaseAddress);
-               cmd->set_vmsize(oneSegment ? 0 : segInfo->fSize);
-               cmd->set_fileoff(segInfo->fFileOffset);
-               cmd->set_filesize(oneSegment ? 0 : segInfo->fFileSize);
-               cmd->set_maxprot(segInfo->fMaxProtection);
-               cmd->set_initprot(segInfo->fInitProtection);
-               // add sections array
-               macho_section<P>* const sections = (macho_section<P>*)&p[sizeof(macho_segment_command<P>)];
-               unsigned int sectionsEmitted = 0;
-               for (int j=0; j < sectionCount; ++j) {
-                       SectionInfo* sectInfo = segInfo->fSections[j];
-                       if ( fWriter.fEmitVirtualSections || !sectInfo->fVirtualSection ) {
-                               macho_section<P>* sect = &sections[sectionsEmitted++];
-                               if ( oneSegment ) {
-                                       // .o file segment does not cover load commands, so recalc at first real section
-                                       if ( sectionsEmitted == 1 ) {
-                                               cmd->set_vmaddr(sectInfo->getBaseAddress());
-                                               cmd->set_fileoff(sectInfo->fFileOffset);
-                                       }
-                                       // <rdar://problem/7712869> if last section is zero-fill don't add size to filesize total
-                                       if ( !sectInfo->fAllZeroFill ) {
-                                               cmd->set_filesize((sectInfo->fFileOffset+sectInfo->fSize)-cmd->fileoff());
-                                       }
-                                       cmd->set_vmsize(sectInfo->getBaseAddress() + sectInfo->fSize);
-                               }
-                               sect->set_sectname(sectInfo->fSectionName);
-                               sect->set_segname(sectInfo->fSegmentName);
-                               sect->set_addr(sectInfo->getBaseAddress());
-                               sect->set_size(sectInfo->fSize);
-                               sect->set_offset(sectInfo->fFileOffset);
-                               sect->set_align(sectInfo->fAlignment);
-                               if ( sectInfo->fRelocCount != 0 ) {
-                                       sect->set_reloff(sectInfo->fRelocOffset * sizeof(macho_relocation_info<P>) + fWriter.fSectionRelocationsAtom->getFileOffset());
-                                       sect->set_nreloc(sectInfo->fRelocCount);
-                               }
-                               if ( sectInfo->fAllZeroFill ) {
-                                       sect->set_flags(S_ZEROFILL);
-                                       sect->set_offset(0);
-                               }
-                               else if ( sectInfo->fAllLazyPointers ) {
-                                       sect->set_flags(S_LAZY_SYMBOL_POINTERS);
-                                       sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
-                               }
-                               else if ( sectInfo->fAllLazyDylibPointers ) {
-                                       sect->set_flags(S_LAZY_DYLIB_SYMBOL_POINTERS);
-                                       sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
-                               }
-                               else if ( sectInfo->fAllNonLazyPointers ) {
-                                       sect->set_flags(S_NON_LAZY_SYMBOL_POINTERS);
-                                       sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
-                               }
-                               else if ( sectInfo->fAllStubs ) {
-                                       sect->set_flags(S_SYMBOL_STUBS | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS);
-                                       sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
-                                       sect->set_reserved2(sectInfo->fSize / sectInfo->fAtoms.size());
-                                       if ( sectInfo->fHasTextLocalRelocs )
-                                               sect->set_flags(sect->flags() | S_ATTR_LOC_RELOC);
-                               }
-                               else if ( sectInfo->fAllSelfModifyingStubs ) {
-                                       sect->set_flags(S_SYMBOL_STUBS | S_ATTR_SELF_MODIFYING_CODE);
-                                       sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
-                                       sect->set_reserved2(sectInfo->fSize / sectInfo->fAtoms.size());
-                               }
-                               else if ( sectInfo->fAllStubHelpers ) {
-                                       sect->set_flags(S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS);
-                                       if ( sectInfo->fHasTextLocalRelocs )
-                                               sect->set_flags(sect->flags() | S_ATTR_LOC_RELOC);
-                               }
-                               else if ( sectInfo->fAtoms.at(0)->getContentType() == ObjectFile::Atom::kCStringType ) {
-                                       sect->set_flags(S_CSTRING_LITERALS);
-                               }
-                               else if ( sectInfo->fAtoms.at(0)->getContentType() == ObjectFile::Atom::kCFIType ) {
-                                       sect->set_flags(S_COALESCED | S_ATTR_NO_TOC | S_ATTR_STRIP_STATIC_SYMS);
-                               }
-                               else if ( (strcmp(sectInfo->fSectionName, "__mod_init_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
-                                       sect->set_flags(S_MOD_INIT_FUNC_POINTERS);
-                               }
-                               else if ( (strcmp(sectInfo->fSectionName, "__mod_term_func") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
-                                       sect->set_flags(S_MOD_TERM_FUNC_POINTERS);
-                               }
-                               else if ( (strcmp(sectInfo->fSectionName, "__textcoal_nt") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
-                                       sect->set_flags(S_COALESCED);
-                               }
-                               else if ( (strcmp(sectInfo->fSectionName, "__const_coal") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
-                                       sect->set_flags(S_COALESCED);
-                               }
-                               else if ( (strcmp(sectInfo->fSectionName, "__interpose") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
-                                       sect->set_flags(S_INTERPOSING);
-                               }
-                               else if ( (strcmp(sectInfo->fSectionName, "__literal4") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
-                                       sect->set_flags(S_4BYTE_LITERALS);
-                               }
-                               else if ( (strcmp(sectInfo->fSectionName, "__literal8") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
-                                       sect->set_flags(S_8BYTE_LITERALS);
-                               }
-                               else if ( (strcmp(sectInfo->fSectionName, "__literal16") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
-                                       sect->set_flags(S_16BYTE_LITERALS);
-                               }
-                               else if ( (strcmp(sectInfo->fSectionName, "__message_refs") == 0) && (strcmp(sectInfo->fSegmentName, "__OBJC") == 0) ) {
-                                       sect->set_flags(S_LITERAL_POINTERS);
-                               }
-                               else if ( (strcmp(sectInfo->fSectionName, "__objc_selrefs") == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
-                                       sect->set_flags(S_LITERAL_POINTERS);
-                               }
-                               else if ( (strcmp(sectInfo->fSectionName, "__cls_refs") == 0) && (strcmp(sectInfo->fSegmentName, "__OBJC") == 0) ) {
-                                       sect->set_flags(S_LITERAL_POINTERS);
-                               }
-                               else if ( (strncmp(sectInfo->fSectionName, "__dof_", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
-                                       sect->set_flags(S_DTRACE_DOF);
-                               }
-                               else if ( (strncmp(sectInfo->fSectionName, "__dof_", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__DATA") == 0) ) {
-                                       sect->set_flags(S_DTRACE_DOF);
-                               }
-                               else if ( (strncmp(sectInfo->fSectionName, "__text", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
-                                       sect->set_flags(S_REGULAR | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS);
-                                       if ( sectInfo->fHasTextLocalRelocs )
-                                               sect->set_flags(sect->flags() | S_ATTR_LOC_RELOC);
-                                       if ( sectInfo->fHasTextExternalRelocs )
-                                               sect->set_flags(sect->flags() | S_ATTR_EXT_RELOC);
-                               }
-                               //fprintf(stderr, "section %s flags=0x%08X\n", sectInfo->fSectionName, sect->flags());
-                       }
-               }
-               p = &p[sizeof(macho_segment_command<P>) + sectionsEmitted*sizeof(macho_section<P>)];
-               cmd->set_cmdsize(sizeof(macho_segment_command<P>) + sectionsEmitted*sizeof(macho_section<P>));
-               cmd->set_nsects(sectionsEmitted);
-       }
-}
-
-
-template <typename A>
-SymbolTableLoadCommandsAtom<A>::SymbolTableLoadCommandsAtom(Writer<A>& writer)
- : LoadCommandAtom<A>(writer), fNeedsDynamicSymbolTable(false)
-{
-       bzero(&fSymbolTable, sizeof(macho_symtab_command<P>));
-       bzero(&fDynamicSymbolTable, sizeof(macho_dysymtab_command<P>));
-       switch ( fWriter.fOptions.outputKind() ) {
-               case Options::kDynamicExecutable:
-               case Options::kDynamicLibrary:
-               case Options::kDynamicBundle:
-               case Options::kDyld:
-               case Options::kKextBundle:
-                       fNeedsDynamicSymbolTable = true;
-                       break;
-               case Options::kObjectFile:
-               case Options::kStaticExecutable:
-                       fNeedsDynamicSymbolTable = false;
-               case Options::kPreload:
-                       fNeedsDynamicSymbolTable = fWriter.fOptions.positionIndependentExecutable();
-                       break;
-       }
-       writer.fSymbolTableCommands = this;
-}
-
-
-
-template <typename A>
-void SymbolTableLoadCommandsAtom<A>::needDynamicTable() 
-{
-       fNeedsDynamicSymbolTable = true;
-}
-       
-
-template <typename A>
-uint64_t SymbolTableLoadCommandsAtom<A>::getSize() const
-{
-       if ( fNeedsDynamicSymbolTable )
-               return this->alignedSize(sizeof(macho_symtab_command<P>) + sizeof(macho_dysymtab_command<P>));
-       else
-               return this->alignedSize(sizeof(macho_symtab_command<P>));
-}
-
-template <typename A>
-void SymbolTableLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
-{
-       // build LC_SYMTAB command
-       macho_symtab_command<P>*   symbolTableCmd = (macho_symtab_command<P>*)buffer;
-       bzero(symbolTableCmd, sizeof(macho_symtab_command<P>));
-       symbolTableCmd->set_cmd(LC_SYMTAB);
-       symbolTableCmd->set_cmdsize(sizeof(macho_symtab_command<P>));
-       symbolTableCmd->set_nsyms(fWriter.fSymbolTableCount);
-       symbolTableCmd->set_symoff(fWriter.fSymbolTableCount == 0 ? 0 : fWriter.fSymbolTableAtom->getFileOffset());
-       symbolTableCmd->set_stroff(fWriter.fStringsAtom->getSize() == 0 ? 0 : fWriter.fStringsAtom->getFileOffset());
-       symbolTableCmd->set_strsize(fWriter.fStringsAtom->getSize());
-
-       // build LC_DYSYMTAB command
-       if ( fNeedsDynamicSymbolTable ) {
-               macho_dysymtab_command<P>* dynamicSymbolTableCmd = (macho_dysymtab_command<P>*)&buffer[sizeof(macho_symtab_command<P>)];
-               bzero(dynamicSymbolTableCmd, sizeof(macho_dysymtab_command<P>));
-               dynamicSymbolTableCmd->set_cmd(LC_DYSYMTAB);
-               dynamicSymbolTableCmd->set_cmdsize(sizeof(macho_dysymtab_command<P>));
-               dynamicSymbolTableCmd->set_ilocalsym(fWriter.fSymbolTableStabsStartIndex);
-               dynamicSymbolTableCmd->set_nlocalsym(fWriter.fSymbolTableStabsCount + fWriter.fSymbolTableLocalCount);
-               dynamicSymbolTableCmd->set_iextdefsym(fWriter.fSymbolTableExportStartIndex);
-               dynamicSymbolTableCmd->set_nextdefsym(fWriter.fSymbolTableExportCount);
-               dynamicSymbolTableCmd->set_iundefsym(fWriter.fSymbolTableImportStartIndex);
-               dynamicSymbolTableCmd->set_nundefsym(fWriter.fSymbolTableImportCount);
-               if ( fWriter.fModuleInfoAtom != NULL ) {
-                       dynamicSymbolTableCmd->set_tocoff(fWriter.fModuleInfoAtom->getTableOfContentsFileOffset());
-                       dynamicSymbolTableCmd->set_ntoc(fWriter.fSymbolTableExportCount);
-                       dynamicSymbolTableCmd->set_modtaboff(fWriter.fModuleInfoAtom->getModuleTableFileOffset());
-                       dynamicSymbolTableCmd->set_nmodtab(1);
-                       dynamicSymbolTableCmd->set_extrefsymoff(fWriter.fModuleInfoAtom->getReferencesFileOffset());
-                       dynamicSymbolTableCmd->set_nextrefsyms(fWriter.fModuleInfoAtom->getReferencesCount());
-               }
-               dynamicSymbolTableCmd->set_indirectsymoff((fWriter.fIndirectTableAtom == NULL) ? 0 : fWriter.fIndirectTableAtom->getFileOffset());
-               dynamicSymbolTableCmd->set_nindirectsyms((fWriter.fIndirectTableAtom == NULL) ? 0 : fWriter.fIndirectTableAtom->fTable.size());
-               if ( fWriter.fOptions.outputKind() != Options::kObjectFile ) {
-                       if ( fWriter.fExternalRelocationsAtom != 0 ) {
-                               dynamicSymbolTableCmd->set_extreloff((fWriter.fExternalRelocs.size()==0) ? 0 : fWriter.fExternalRelocationsAtom->getFileOffset());
-                               dynamicSymbolTableCmd->set_nextrel(fWriter.fExternalRelocs.size());
-                       }
-                       if ( fWriter.fLocalRelocationsAtom != 0 ) {
-                               dynamicSymbolTableCmd->set_locreloff((fWriter.fInternalRelocs.size()==0) ? 0 : fWriter.fLocalRelocationsAtom->getFileOffset());
-                               dynamicSymbolTableCmd->set_nlocrel(fWriter.fInternalRelocs.size());
-                       }
-               }
-       }
-}
-
-
-template <typename A>
-unsigned int SymbolTableLoadCommandsAtom<A>::commandCount()
-{
-       return fNeedsDynamicSymbolTable ? 2 : 1;
-}
-
-template <typename A>
-uint64_t DyldLoadCommandsAtom<A>::getSize() const
-{
-       return this->alignedSize(sizeof(macho_dylinker_command<P>) + strlen("/usr/lib/dyld") + 1);
-}
-
-template <typename A>
-void DyldLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
-{
-       uint64_t size = this->getSize();
-       bzero(buffer, size);
-       macho_dylinker_command<P>* cmd = (macho_dylinker_command<P>*)buffer;
-       if ( fWriter.fOptions.outputKind() == Options::kDyld )
-               cmd->set_cmd(LC_ID_DYLINKER);
-       else
-               cmd->set_cmd(LC_LOAD_DYLINKER);
-       cmd->set_cmdsize(this->getSize());
-       cmd->set_name_offset();
-       strcpy((char*)&buffer[sizeof(macho_dylinker_command<P>)], "/usr/lib/dyld");
-}
-
-template <typename A>
-uint64_t AllowableClientLoadCommandsAtom<A>::getSize() const
-{
-       return this->alignedSize(sizeof(macho_sub_client_command<P>) + strlen(this->clientString) + 1);
-}
-
-template <typename A>
-void AllowableClientLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
-{
-       uint64_t size = this->getSize();
-
-       bzero(buffer, size);
-       macho_sub_client_command<P>* cmd = (macho_sub_client_command<P>*)buffer;
-       cmd->set_cmd(LC_SUB_CLIENT);
-       cmd->set_cmdsize(size);
-       cmd->set_client_offset();
-       strcpy((char*)&buffer[sizeof(macho_sub_client_command<P>)], this->clientString);
-
-}
-
-template <typename A>
-uint64_t DylibLoadCommandsAtom<A>::getSize() const
-{
-       if ( fOptimizedAway ) {
-               return 0;
-       }
-       else {
-               const char* path = fInfo.reader->getInstallPath();
-               return this->alignedSize(sizeof(macho_dylib_command<P>) + strlen(path) + 1);
-       }
-}
-
-template <typename A>
-void DylibLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
-{
-       if ( fOptimizedAway ) 
-               return;
-       uint64_t size = this->getSize();
-       bzero(buffer, size);
-       const char* path = fInfo.reader->getInstallPath();
-       macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)buffer;
-       // <rdar://problem/5529626> If only weak_import symbols are used, linker should use LD_LOAD_WEAK_DYLIB
-       bool autoWeakLoadDylib = ( (fWriter.fDylibReadersWithWeakImports.count(fInfo.reader) > 0) 
-                                                       && (fWriter.fDylibReadersWithNonWeakImports.count(fInfo.reader) == 0) );
-       if ( fInfo.options.fLazyLoad )
-               cmd->set_cmd(LC_LAZY_LOAD_DYLIB);
-       else if ( fInfo.options.fWeakImport || autoWeakLoadDylib )
-               cmd->set_cmd(LC_LOAD_WEAK_DYLIB);
-       else if ( fInfo.options.fReExport && fWriter.fOptions.useSimplifiedDylibReExports() )
-               cmd->set_cmd(LC_REEXPORT_DYLIB);
-       else
-               cmd->set_cmd(LC_LOAD_DYLIB);
-       cmd->set_cmdsize(this->getSize());
-       cmd->set_timestamp(2);  // needs to be some constant value that is different than DylibIDLoadCommandsAtom uses
-       cmd->set_current_version(fInfo.reader->getCurrentVersion());
-       cmd->set_compatibility_version(fInfo.reader->getCompatibilityVersion());
-       cmd->set_name_offset();
-       strcpy((char*)&buffer[sizeof(macho_dylib_command<P>)], path);
-}
-
-
-
-template <typename A>
-uint64_t DylibIDLoadCommandsAtom<A>::getSize() const
-{
-       return this->alignedSize(sizeof(macho_dylib_command<P>) + strlen(fWriter.fOptions.installPath()) + 1);
-}
-
-template <typename A>
-void DylibIDLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
-{
-       uint64_t size = this->getSize();
-       bzero(buffer, size);
-       macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)buffer;
-       cmd->set_cmd(LC_ID_DYLIB);
-       cmd->set_cmdsize(this->getSize());
-       cmd->set_name_offset();
-       cmd->set_timestamp(1);  // needs to be some constant value that is different than DylibLoadCommandsAtom uses
-       cmd->set_current_version(fWriter.fOptions.currentVersion());
-       cmd->set_compatibility_version(fWriter.fOptions.compatibilityVersion());
-       strcpy((char*)&buffer[sizeof(macho_dylib_command<P>)], fWriter.fOptions.installPath());
-}
-
-
-template <typename A>
-void RoutinesLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
-{
-       uint64_t initAddr = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
-       if (fWriter.fEntryPoint->isThumb())
-               initAddr |= 1ULL;
-       bzero(buffer, sizeof(macho_routines_command<P>));
-       macho_routines_command<P>* cmd = (macho_routines_command<P>*)buffer;
-       cmd->set_cmd(macho_routines_command<P>::CMD);
-       cmd->set_cmdsize(this->getSize());
-       cmd->set_init_address(initAddr);
-}
-
-
-template <typename A>
-uint64_t SubUmbrellaLoadCommandsAtom<A>::getSize() const
-{
-       return this->alignedSize(sizeof(macho_sub_umbrella_command<P>) + strlen(fName) + 1);
-}
-
-template <typename A>
-void SubUmbrellaLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
-{
-       uint64_t size = this->getSize();
-       bzero(buffer, size);
-       macho_sub_umbrella_command<P>* cmd = (macho_sub_umbrella_command<P>*)buffer;
-       cmd->set_cmd(LC_SUB_UMBRELLA);
-       cmd->set_cmdsize(this->getSize());
-       cmd->set_sub_umbrella_offset();
-       strcpy((char*)&buffer[sizeof(macho_sub_umbrella_command<P>)], fName);
-}
-
-template <typename A>
-void UUIDLoadCommandAtom<A>::generate() 
-{
-       switch ( fWriter.fOptions.getUUIDMode() ) {
-               case Options::kUUIDNone: 
-                       fEmit = false;
-                       break;
-               case Options::kUUIDRandom:
-                       ::uuid_generate_random(fUUID);
-                       fEmit = true;
-                       break;
-               case Options::kUUIDContent: 
-                       bzero(fUUID, 16);
-                       fEmit = true;
-                       break;
-       }
-}
-
-template <typename A>
-void UUIDLoadCommandAtom<A>::setContent(const uint8_t uuid[16]) 
-{
-       memcpy(fUUID, uuid, 16);
-}
-
-template <typename A>
-void UUIDLoadCommandAtom<A>::copyRawContent(uint8_t buffer[]) const
-{
-       if (fEmit) {
-               uint64_t size = this->getSize();
-               bzero(buffer, size);
-               macho_uuid_command<P>* cmd = (macho_uuid_command<P>*)buffer;
-               cmd->set_cmd(LC_UUID);
-               cmd->set_cmdsize(this->getSize());
-               cmd->set_uuid((uint8_t*)fUUID);
-       }
-}
-
-
-template <typename A>
-uint64_t SubLibraryLoadCommandsAtom<A>::getSize() const
-{
-       return this->alignedSize(sizeof(macho_sub_library_command<P>) + fNameLength + 1);
-}
-
-template <typename A>
-void SubLibraryLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
-{
-       uint64_t size = this->getSize();
-       bzero(buffer, size);
-       macho_sub_library_command<P>* cmd = (macho_sub_library_command<P>*)buffer;
-       cmd->set_cmd(LC_SUB_LIBRARY);
-       cmd->set_cmdsize(this->getSize());
-       cmd->set_sub_library_offset();
-       strncpy((char*)&buffer[sizeof(macho_sub_library_command<P>)], fNameStart, fNameLength);
-       buffer[sizeof(macho_sub_library_command<P>)+fNameLength] = '\0';
-}
-
-template <typename A>
-uint64_t UmbrellaLoadCommandsAtom<A>::getSize() const
-{
-       return this->alignedSize(sizeof(macho_sub_framework_command<P>) + strlen(fName) + 1);
-}
-
-template <typename A>
-void UmbrellaLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
-{
-       uint64_t size = this->getSize();
-       bzero(buffer, size);
-       macho_sub_framework_command<P>* cmd = (macho_sub_framework_command<P>*)buffer;
-       cmd->set_cmd(LC_SUB_FRAMEWORK);
-       cmd->set_cmdsize(this->getSize());
-       cmd->set_umbrella_offset();
-       strcpy((char*)&buffer[sizeof(macho_sub_framework_command<P>)], fName);
-}
-
-template <>
-uint64_t ThreadsLoadCommandsAtom<ppc>::getSize() const
-{
-       return this->alignedSize(16 + 40*4);    // base size + PPC_THREAD_STATE_COUNT * 4
-}
-
-template <>
-uint64_t ThreadsLoadCommandsAtom<ppc64>::getSize() const
-{
-       return this->alignedSize(16 + 76*4);    // base size + PPC_THREAD_STATE64_COUNT * 4
-}
-
-template <>
-uint64_t ThreadsLoadCommandsAtom<x86>::getSize() const
-{
-       return this->alignedSize(16 + 16*4);    // base size + i386_THREAD_STATE_COUNT * 4
-}
-
-template <>
-uint64_t ThreadsLoadCommandsAtom<x86_64>::getSize() const
-{
-       return this->alignedSize(16 + x86_THREAD_STATE64_COUNT * 4); 
-}
-
-// We should be picking it up from a header
-template <>
-uint64_t ThreadsLoadCommandsAtom<arm>::getSize() const
-{
-       return this->alignedSize(16 + 17 * 4); // base size + ARM_THREAD_STATE_COUNT * 4
-}
-
-template <>
-void ThreadsLoadCommandsAtom<ppc>::copyRawContent(uint8_t buffer[]) const
-{
-       uint64_t size = this->getSize();
-       uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
-       bzero(buffer, size);
-       macho_thread_command<ppc::P>* cmd = (macho_thread_command<ppc::P>*)buffer;
-       cmd->set_cmd(LC_UNIXTHREAD);
-       cmd->set_cmdsize(size);
-       cmd->set_flavor(1);                             // PPC_THREAD_STATE
-       cmd->set_count(40);                             // PPC_THREAD_STATE_COUNT;
-       cmd->set_thread_register(0, start);
-       if ( fWriter.fOptions.hasCustomStack() )
-               cmd->set_thread_register(3, fWriter.fOptions.customStackAddr());        // r1
-}
-
-
-template <>
-void ThreadsLoadCommandsAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
-{
-       uint64_t size = this->getSize();
-       uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
-       bzero(buffer, size);
-       macho_thread_command<ppc64::P>* cmd = (macho_thread_command<ppc64::P>*)buffer;
-       cmd->set_cmd(LC_UNIXTHREAD);
-       cmd->set_cmdsize(size);
-       cmd->set_flavor(5);                             // PPC_THREAD_STATE64
-       cmd->set_count(76);                             // PPC_THREAD_STATE64_COUNT;
-       cmd->set_thread_register(0, start);
-       if ( fWriter.fOptions.hasCustomStack() )
-               cmd->set_thread_register(3, fWriter.fOptions.customStackAddr());        // r1
-}
-
-template <>
-void ThreadsLoadCommandsAtom<x86>::copyRawContent(uint8_t buffer[]) const
-{
-       uint64_t size = this->getSize();
-       uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
-       bzero(buffer, size);
-       macho_thread_command<x86::P>* cmd = (macho_thread_command<x86::P>*)buffer;
-       cmd->set_cmd(LC_UNIXTHREAD);
-       cmd->set_cmdsize(size);
-       cmd->set_flavor(1);                             // i386_THREAD_STATE
-       cmd->set_count(16);                             // i386_THREAD_STATE_COUNT;
-       cmd->set_thread_register(10, start);
-       if ( fWriter.fOptions.hasCustomStack() )
-               cmd->set_thread_register(7, fWriter.fOptions.customStackAddr());        // esp
-}
-
-template <>
-void ThreadsLoadCommandsAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
-{
-       uint64_t size = this->getSize();
-       uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
-       bzero(buffer, size);
-       macho_thread_command<x86_64::P>* cmd = (macho_thread_command<x86_64::P>*)buffer;
-       cmd->set_cmd(LC_UNIXTHREAD);
-       cmd->set_cmdsize(size);
-       cmd->set_flavor(x86_THREAD_STATE64);                    
-       cmd->set_count(x86_THREAD_STATE64_COUNT);       
-       cmd->set_thread_register(16, start);            // rip 
-       if ( fWriter.fOptions.hasCustomStack() )
-               cmd->set_thread_register(7, fWriter.fOptions.customStackAddr());        // uesp
-}
-
-template <>
-void ThreadsLoadCommandsAtom<arm>::copyRawContent(uint8_t buffer[]) const
-{
-       uint64_t size = this->getSize();
-       uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
-       if ( fWriter.fEntryPoint->isThumb() )
-               start |= 1ULL;
-       bzero(buffer, size);
-       macho_thread_command<arm::P>* cmd = (macho_thread_command<arm::P>*)buffer;
-       cmd->set_cmd(LC_UNIXTHREAD);
-       cmd->set_cmdsize(size);
-       cmd->set_flavor(1);                     
-       cmd->set_count(17);     
-       cmd->set_thread_register(15, start);            // pc
-       if ( fWriter.fOptions.hasCustomStack() )
-               cmd->set_thread_register(13, fWriter.fOptions.customStackAddr());       // FIXME: sp?
-}
-
-template <typename A>
-uint64_t RPathLoadCommandsAtom<A>::getSize() const
-{
-       return this->alignedSize(sizeof(macho_rpath_command<P>) + strlen(fPath) + 1);
-}
-
-template <typename A>
-void RPathLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
-{
-       uint64_t size = this->getSize();
-       bzero(buffer, size);
-       macho_rpath_command<P>* cmd = (macho_rpath_command<P>*)buffer;
-       cmd->set_cmd(LC_RPATH);
-       cmd->set_cmdsize(this->getSize());
-       cmd->set_path_offset();
-       strcpy((char*)&buffer[sizeof(macho_rpath_command<P>)], fPath);
-}
-
-
-
-template <typename A>
-void EncryptionLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
-{
-       uint64_t size = this->getSize();
-       bzero(buffer, size);
-       macho_encryption_info_command<P>* cmd = (macho_encryption_info_command<P>*)buffer;
-       cmd->set_cmd(LC_ENCRYPTION_INFO);
-       cmd->set_cmdsize(this->getSize());
-       cmd->set_cryptoff(fStartOffset);
-       cmd->set_cryptsize(fEndOffset-fStartOffset);
-       cmd->set_cryptid(0);
-}
-
-
-
-template <typename A>
-void LoadCommandsPaddingAtom<A>::copyRawContent(uint8_t buffer[]) const
-{
-       bzero(buffer, fSize);
-}
-
-template <typename A>
-void LoadCommandsPaddingAtom<A>::setSize(uint64_t newSize) 
-{ 
-       fSize = newSize; 
-       // this resizing by-passes the way fLargestAtomSize is set, so re-check here
-       if ( fWriter.fLargestAtomSize < newSize )
-               fWriter.fLargestAtomSize = newSize;
-}
-
-template <typename A>
-void UnwindInfoAtom<A>::addUnwindInfo(ObjectFile::Atom* func, uint32_t offset, uint32_t encoding, 
-                                                                               ObjectFile::Reference* fdeRef, ObjectFile::Reference* lsdaRef,
-                                                                               ObjectFile::Atom* personalityPointer) 
-{ 
-       Info info;
-       info.func = func;
-       if ( fdeRef != NULL )  
-               info.fde = &fdeRef->getTarget();
-       else 
-               info.fde = NULL;
-       if ( lsdaRef != NULL )  {
-               info.lsda = &lsdaRef->getTarget();
-               info.lsdaOffset = lsdaRef->getTargetOffset();
-       }
-       else {
-               info.lsda = NULL;
-               info.lsdaOffset = 0;
-       }
-       info.personalityPointer = personalityPointer;
-       info.encoding = encoding;
-       fInfos.push_back(info);
-       //fprintf(stderr, "addUnwindInfo() encoding=0x%08X, lsda=%p, lsdaOffset=%d, person=%p, func=%s\n", 
-       //                              encoding, info.lsda, info.lsdaOffset, personalityPointer, func->getDisplayName());
-}
-
-template <>
-bool UnwindInfoAtom<x86>::encodingMeansUseDwarf(compact_unwind_encoding_t encoding)
-{
-       return ( (encoding & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF);
-}
-
-template <>
-bool UnwindInfoAtom<x86_64>::encodingMeansUseDwarf(compact_unwind_encoding_t encoding)
-{
-       return ( (encoding & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF);
-}
-
-template <typename A>
-bool UnwindInfoAtom<A>::encodingMeansUseDwarf(compact_unwind_encoding_t encoding)
-{
-       return false;
-}
-
-
-template <typename A>
-void UnwindInfoAtom<A>::compressDuplicates(std::vector<Info>& uniqueInfos)
-{
-       // build new list removing entries where next function has same encoding 
-       uniqueInfos.reserve(fInfos.size());
-       Info last;
-       last.func = NULL;
-       last.lsda = NULL;
-       last.lsdaOffset = 0;
-       last.personalityPointer = NULL;
-       last.encoding = 0xFFFFFFFF;
-       for(typename std::vector<Info>::iterator it=fInfos.begin(); it != fInfos.end(); ++it) {
-               Info& newInfo = *it;
-               bool newNeedsDwarf = encodingMeansUseDwarf(newInfo.encoding);
-               // remove infos which have same encoding and personalityPointer as last one
-               if ( newNeedsDwarf || (newInfo.encoding != last.encoding) || (newInfo.personalityPointer != last.personalityPointer) 
-                                               || (newInfo.lsda != NULL) || (last.lsda != NULL) ) {
-                       uniqueInfos.push_back(newInfo);
-               }
-               last = newInfo;
-       }
-       //fprintf(stderr, "compressDuplicates() fInfos.size()=%lu, uniqueInfos.size()=%lu\n", fInfos.size(), uniqueInfos.size());
-}
-
-template <typename A>
-void UnwindInfoAtom<A>::findCommonEncoding(const std::vector<Info>& uniqueInfos, std::map<uint32_t, unsigned int>& commonEncodings)
-{
-       // scan infos to get frequency counts for each encoding
-       std::map<uint32_t, unsigned int> encodingsUsed;
-       unsigned int mostCommonEncodingUsageCount = 0;
-       for(typename std::vector<Info>::const_iterator it=uniqueInfos.begin(); it != uniqueInfos.end(); ++it) {
-               // never put dwarf into common table
-               if ( encodingMeansUseDwarf(it->encoding) )
-                       continue;
-               std::map<uint32_t, unsigned int>::iterator pos = encodingsUsed.find(it->encoding);
-               if ( pos == encodingsUsed.end() ) {
-                       encodingsUsed[it->encoding] = 1;
-               }
-               else {
-                       encodingsUsed[it->encoding] += 1;
-                       if ( mostCommonEncodingUsageCount < encodingsUsed[it->encoding] )
-                               mostCommonEncodingUsageCount = encodingsUsed[it->encoding];
-               }
-       }
-       // put the most common encodings into the common table, but at most 127 of them
-       for(unsigned int usages=mostCommonEncodingUsageCount; usages > 1; --usages) {
-               for (std::map<uint32_t, unsigned int>::iterator euit=encodingsUsed.begin(); euit != encodingsUsed.end(); ++euit) {
-                       if ( euit->second == usages ) {
-                               unsigned int size = commonEncodings.size();
-                               if ( size < 127 ) {
-                                       commonEncodings[euit->first] = size;
-                               }
-                       }
-               }
-       }
-}
-
-template <typename A>
-void UnwindInfoAtom<A>::makeLsdaIndex(const std::vector<Info>& uniqueInfos, std::map<ObjectFile::Atom*, uint32_t>& lsdaIndexOffsetMap)
-{
-       for(typename std::vector<Info>::const_iterator it=uniqueInfos.begin(); it != uniqueInfos.end(); ++it) {
-               lsdaIndexOffsetMap[it->func] = fLSDAIndex.size() * sizeof(macho_unwind_info_section_header_lsda_index_entry<P>);
-               if ( it->lsda != NULL ) {
-                       LSDAEntry entry;
-                       entry.func = it->func;
-                       entry.lsda = it->lsda;
-                       entry.lsdaOffset = it->lsdaOffset;
-                       fLSDAIndex.push_back(entry);
-               }
-       }
-}
-
-template <typename A>
-void UnwindInfoAtom<A>::makePersonalityIndex(std::vector<Info>& uniqueInfos)
-{
-       for(typename std::vector<Info>::iterator it=uniqueInfos.begin(); it != uniqueInfos.end(); ++it) {
-               if ( it->personalityPointer != NULL ) {
-                       std::map<ObjectFile::Atom*, uint32_t>::iterator pos = fPersonalityIndexMap.find(it->personalityPointer);
-                       if ( pos == fPersonalityIndexMap.end() ) {
-                               const uint32_t nextIndex = fPersonalityIndexMap.size() + 1;
-                               fPersonalityIndexMap[it->personalityPointer] = nextIndex;
-                       }
-                       uint32_t personalityIndex = fPersonalityIndexMap[it->personalityPointer];
-                       it->encoding |= (personalityIndex << (__builtin_ctz(UNWIND_PERSONALITY_MASK)) );
-               }
-       }
-}
-
-template <typename A>
-unsigned int UnwindInfoAtom<A>::makeRegularSecondLevelPage(const std::vector<Info>& uniqueInfos, uint32_t pageSize,  
-                                                                                                                       unsigned int endIndex, uint8_t*& pageEnd)
-{
-       const unsigned int maxEntriesPerPage = (pageSize - sizeof(unwind_info_regular_second_level_page_header))/sizeof(unwind_info_regular_second_level_entry);
-       const unsigned int entriesToAdd = ((endIndex > maxEntriesPerPage) ? maxEntriesPerPage : endIndex);
-       uint8_t* pageStart = pageEnd 
-                                               - entriesToAdd*sizeof(unwind_info_regular_second_level_entry) 
-                                               - sizeof(unwind_info_regular_second_level_page_header);
-       macho_unwind_info_regular_second_level_page_header<P>* page = (macho_unwind_info_regular_second_level_page_header<P>*)pageStart;
-       page->set_kind(UNWIND_SECOND_LEVEL_REGULAR);
-       page->set_entryPageOffset(sizeof(macho_unwind_info_regular_second_level_page_header<P>));
-       page->set_entryCount(entriesToAdd);
-       macho_unwind_info_regular_second_level_entry<P>* entryTable = (macho_unwind_info_regular_second_level_entry<P>*)(pageStart + page->entryPageOffset());
-       for (unsigned int i=0; i < entriesToAdd; ++i) {
-               const Info& info = uniqueInfos[endIndex-entriesToAdd+i];
-               entryTable[i].set_functionOffset(0);
-               entryTable[i].set_encoding(info.encoding);
-               RegFixUp fixup;
-               fixup.contentPointer = (uint8_t*)(&entryTable[i]);
-               fixup.func = info.func;
-               fixup.fde = ( encodingMeansUseDwarf(info.encoding) ? info.fde : NULL );
-               fRegFixUps.push_back(fixup);
-       }
-       //fprintf(stderr, "regular page with %u entries\n", entriesToAdd);
-       pageEnd = pageStart;
-       return endIndex - entriesToAdd;
-}
-
-
-template <typename A>
-unsigned int UnwindInfoAtom<A>::makeCompressedSecondLevelPage(const std::vector<Info>& uniqueInfos,   
-                                                                                                                       const std::map<uint32_t,unsigned int> commonEncodings,  
-                                                                                                                       uint32_t pageSize, unsigned int endIndex, uint8_t*& pageEnd)
-{
-       const bool log = false;
-       if (log) fprintf(stderr, "makeCompressedSecondLevelPage(pageSize=%u, endIndex=%u)\n", pageSize, endIndex);
-       // first pass calculates how many compressed entries we could fit in this sized page
-       // keep adding entries to page until:
-       //  1) encoding table plus entry table plus header exceed page size
-       //  2) the file offset delta from the first to last function > 24 bits
-       //  3) custom encoding index reachs 255
-       //  4) run out of uniqueInfos to encode
-       std::map<uint32_t, unsigned int> pageSpecificEncodings;
-       uint32_t space4 =  (pageSize - sizeof(unwind_info_compressed_second_level_page_header))/sizeof(uint32_t);
-       std::vector<uint8_t> encodingIndexes;
-       int index = endIndex-1;
-       int entryCount = 0;
-       uint64_t lastEntryAddress = uniqueInfos[index].func->getAddress();
-       bool canDo = true;
-       while ( canDo && (index >= 0) ) {
-               const Info& info = uniqueInfos[index--];
-               // compute encoding index
-               unsigned int encodingIndex;
-               std::map<uint32_t, unsigned int>::const_iterator pos = commonEncodings.find(info.encoding);
-               if ( pos != commonEncodings.end() ) {
-                       encodingIndex = pos->second;
-               }
-               else {
-                       // no commmon entry, so add one on this page
-                       uint32_t encoding = info.encoding;
-                       if ( encodingMeansUseDwarf(encoding) ) {
-                               // make unique pseudo encoding so this dwarf will gets is own encoding entry slot
-                               encoding += (index+1);
-                       }
-                       std::map<uint32_t, unsigned int>::iterator ppos = pageSpecificEncodings.find(encoding);
-                       if ( ppos != pageSpecificEncodings.end() ) {
-                               encodingIndex = pos->second;
-                       }
-                       else {
-                               encodingIndex = commonEncodings.size() + pageSpecificEncodings.size();
-                               if ( encodingIndex <= 255 ) {
-                                       pageSpecificEncodings[encoding] = encodingIndex;
-                               }
-                               else {
-                                       canDo = false; // case 3)
-                                       if (log) fprintf(stderr, "end of compressed page with %u entries, %lu custom encodings because too many custom encodings\n", 
-                                                                                       entryCount, pageSpecificEncodings.size());
-                               }
-                       }
-               }
-               if ( canDo ) 
-                       encodingIndexes.push_back(encodingIndex);
-               // compute function offset
-               uint32_t funcOffsetWithInPage = lastEntryAddress - info.func->getAddress();
-               if ( funcOffsetWithInPage > 0x00FFFF00 ) {
-                       // don't use 0x00FFFFFF because addresses may vary after atoms are laid out again
-                       canDo = false; // case 2)
-                       if (log) fprintf(stderr, "can't use compressed page with %u entries because function offset too big\n", entryCount);
-               }
-               else {
-                       ++entryCount;
-               }
-               // check room for entry
-               if ( (pageSpecificEncodings.size()+entryCount) >= space4 ) {
-                       canDo = false; // case 1)
-                       --entryCount;
-                       if (log) fprintf(stderr, "end of compressed page with %u entries because full\n", entryCount);
-               }
-               //if (log) fprintf(stderr, "space4=%d, pageSpecificEncodings.size()=%ld, entryCount=%d\n", space4, pageSpecificEncodings.size(), entryCount);
-       }
-       
-       // check for cases where it would be better to use a regular (non-compressed) page
-       const unsigned int compressPageUsed = sizeof(unwind_info_compressed_second_level_page_header) 
-                                                               + pageSpecificEncodings.size()*sizeof(uint32_t)
-                                                               + entryCount*sizeof(uint32_t);
-       if ( (compressPageUsed < (pageSize-4) && (index >= 0) ) ) {
-               const int regularEntriesPerPage = (pageSize - sizeof(unwind_info_regular_second_level_page_header))/sizeof(unwind_info_regular_second_level_entry);
-               if ( entryCount < regularEntriesPerPage ) {
-                       return makeRegularSecondLevelPage(uniqueInfos, pageSize, endIndex, pageEnd);
-               }
-       }
-       
-       // check if we need any padding because adding another entry would take 8 bytes but only have room for 4
-       uint32_t pad = 0;
-       if ( compressPageUsed == (pageSize-4) )
-               pad = 4;
-       
-       // second pass fills in page 
-       uint8_t* pageStart = pageEnd - compressPageUsed - pad;
-       macho_unwind_info_compressed_second_level_page_header<P>* page = (macho_unwind_info_compressed_second_level_page_header<P>*)pageStart;
-       page->set_kind(UNWIND_SECOND_LEVEL_COMPRESSED);
-       page->set_entryPageOffset(sizeof(macho_unwind_info_compressed_second_level_page_header<P>));
-       page->set_entryCount(entryCount);
-       page->set_encodingsPageOffset(page->entryPageOffset()+entryCount*sizeof(uint32_t));
-       page->set_encodingsCount(pageSpecificEncodings.size());
-       uint32_t* const encodingsArray = (uint32_t*)&pageStart[page->encodingsPageOffset()];
-       // fill in entry table
-       uint32_t* const entiresArray = (uint32_t*)&pageStart[page->entryPageOffset()];
-       ObjectFile::Atom* firstFunc = uniqueInfos[endIndex-entryCount].func;
-       for(unsigned int i=endIndex-entryCount; i < endIndex; ++i) {
-               const Info& info = uniqueInfos[i];
-               uint8_t encodingIndex;
-               if ( encodingMeansUseDwarf(info.encoding) ) {
-                       // dwarf entries are always in page specific encodings
-                       encodingIndex = pageSpecificEncodings[info.encoding+i];
-               }
-               else {
-                       std::map<uint32_t, unsigned int>::const_iterator pos = commonEncodings.find(info.encoding);
-                       if ( pos != commonEncodings.end() ) 
-                               encodingIndex = pos->second;
-                       else 
-                               encodingIndex = pageSpecificEncodings[info.encoding];
-               }
-               uint32_t entryIndex = i - endIndex + entryCount;
-               A::P::E::set32(entiresArray[entryIndex], encodingIndex << 24);
-               CompressedFixUp                 funcStartFixUp;
-               funcStartFixUp.contentPointer = (uint8_t*)(&entiresArray[entryIndex]);
-               funcStartFixUp.func = info.func;
-               funcStartFixUp.fromFunc = firstFunc;
-               fCompressedFixUps.push_back(funcStartFixUp);
-               if ( encodingMeansUseDwarf(info.encoding) ) {
-                       CompressedEncodingFixUp dwarfStartFixup;
-                       dwarfStartFixup.contentPointer = (uint8_t*)(&encodingsArray[encodingIndex-commonEncodings.size()]); 
-                       dwarfStartFixup.fde = info.fde;
-                       fCompressedEncodingFixUps.push_back(dwarfStartFixup);
-               }
-       }
-       // fill in encodings table
-       for(std::map<uint32_t, unsigned int>::const_iterator it = pageSpecificEncodings.begin(); it != pageSpecificEncodings.end(); ++it) {
-               A::P::E::set32(encodingsArray[it->second-commonEncodings.size()], it->first);
-       }
-       
-       if (log) fprintf(stderr, "compressed page with %u entries, %lu custom encodings\n", entryCount, pageSpecificEncodings.size());
-       
-       // update pageEnd;
-       pageEnd = pageStart;
-       return endIndex-entryCount;  // endIndex for next page
-}
-
-template <> void UnwindInfoAtom<ppc>::generate() { }
-template <> void UnwindInfoAtom<ppc64>::generate() { }
-template <> void UnwindInfoAtom<arm>::generate() { }
-
-
-template <typename A>
-void UnwindInfoAtom<A>::generate()
-{
-       // only generate table if there are functions with unwind info
-       if ( fInfos.size() > 0 ) {              
-               // find offset of end of __unwind_info section 
-               SectionInfo* unwindSectionInfo = (SectionInfo*)this->getSection();
-
-               // build new list that has proper offsetInImage and remove entries where next function has same encoding 
-               std::vector<Info> uniqueInfos;
-               this->compressDuplicates(uniqueInfos);
-               
-               // build personality index, update encodings with personality index
-               this->makePersonalityIndex(uniqueInfos);
-               if ( fPersonalityIndexMap.size() > 3 )
-                       throw "too many personality routines for compact unwind to encode";
-               
-               // put the most common encodings into the common table, but at most 127 of them
-               std::map<uint32_t, unsigned int> commonEncodings;
-               this->findCommonEncoding(uniqueInfos, commonEncodings);
-               
-               // build lsda index
-               std::map<ObjectFile::Atom*, uint32_t> lsdaIndexOffsetMap;
-               this->makeLsdaIndex(uniqueInfos, lsdaIndexOffsetMap);
-               
-               // calculate worst case size for all unwind info pages when allocating buffer
-               const unsigned int entriesPerRegularPage = (4096-sizeof(unwind_info_regular_second_level_page_header))/sizeof(unwind_info_regular_second_level_entry);
-               const unsigned int pageCount = ((uniqueInfos.size() - 1)/entriesPerRegularPage) + 1;
-               fPagesContentForDelete = (uint8_t*)calloc(pageCount,4096);
-               fPagesSize = 0;
-               if ( fPagesContentForDelete == NULL )
-                       throw "could not allocate space for compact unwind info";
-               ObjectFile::Atom* secondLevelFirstFuncs[pageCount*3];
-               uint8_t* secondLevelPagesStarts[pageCount*3];
-               
-               // make last second level page smaller so that all other second level pages can be page aligned
-               uint32_t maxLastPageSize = unwindSectionInfo->fFileOffset % 4096;
-               uint32_t tailPad = 0;
-               if ( maxLastPageSize < 128 ) {
-                       tailPad = maxLastPageSize;
-                       maxLastPageSize = 4096;
-               }
-
-               // fill in pages in reverse order
-               unsigned int endIndex = uniqueInfos.size();
-               unsigned int secondLevelPageCount = 0;
-               uint8_t* pageEnd = &fPagesContentForDelete[pageCount*4096];
-               uint32_t pageSize = maxLastPageSize;
-               while ( endIndex > 0 ) {
-                       endIndex = makeCompressedSecondLevelPage(uniqueInfos, commonEncodings, pageSize, endIndex, pageEnd);
-                       secondLevelPagesStarts[secondLevelPageCount] = pageEnd;
-                       secondLevelFirstFuncs[secondLevelPageCount] = uniqueInfos[endIndex].func;
-                       ++secondLevelPageCount;
-                       pageSize = 4096;  // last page can be odd size, make rest up to 4096 bytes in size
-               }
-               fPagesContent = pageEnd;
-               fPagesSize = &fPagesContentForDelete[pageCount*4096] - pageEnd;
-
-               // calculate section layout
-               const uint32_t commonEncodingsArraySectionOffset = sizeof(macho_unwind_info_section_header<P>);
-               const uint32_t commonEncodingsArrayCount = commonEncodings.size();
-               const uint32_t commonEncodingsArraySize = commonEncodingsArrayCount * sizeof(compact_unwind_encoding_t);
-               const uint32_t personalityArraySectionOffset = commonEncodingsArraySectionOffset + commonEncodingsArraySize;
-               const uint32_t personalityArrayCount = fPersonalityIndexMap.size();
-               const uint32_t personalityArraySize = personalityArrayCount * sizeof(uint32_t);
-               const uint32_t indexSectionOffset = personalityArraySectionOffset + personalityArraySize;
-               const uint32_t indexCount = secondLevelPageCount+1;
-               const uint32_t indexSize = indexCount * sizeof(macho_unwind_info_section_header_index_entry<P>);
-               const uint32_t lsdaIndexArraySectionOffset = indexSectionOffset + indexSize;
-               const uint32_t lsdaIndexArrayCount = fLSDAIndex.size();
-               const uint32_t lsdaIndexArraySize = lsdaIndexArrayCount * sizeof(macho_unwind_info_section_header_lsda_index_entry<P>);
-               const uint32_t headerEndSectionOffset = lsdaIndexArraySectionOffset + lsdaIndexArraySize;
-
-
-               // allocate and fill in section header
-               fHeaderSize = headerEndSectionOffset;
-               fHeaderContent = new uint8_t[fHeaderSize];
-               bzero(fHeaderContent, fHeaderSize);
-               macho_unwind_info_section_header<P>* sectionHeader = (macho_unwind_info_section_header<P>*)fHeaderContent;
-               sectionHeader->set_version(UNWIND_SECTION_VERSION);
-               sectionHeader->set_commonEncodingsArraySectionOffset(commonEncodingsArraySectionOffset);
-               sectionHeader->set_commonEncodingsArrayCount(commonEncodingsArrayCount);
-               sectionHeader->set_personalityArraySectionOffset(personalityArraySectionOffset);
-               sectionHeader->set_personalityArrayCount(personalityArrayCount);
-               sectionHeader->set_indexSectionOffset(indexSectionOffset);
-               sectionHeader->set_indexCount(indexCount);
-               
-               // copy common encodings
-               uint32_t* commonEncodingsTable = (uint32_t*)&fHeaderContent[commonEncodingsArraySectionOffset];
-               for (std::map<uint32_t, unsigned int>::iterator it=commonEncodings.begin(); it != commonEncodings.end(); ++it)
-                       A::P::E::set32(commonEncodingsTable[it->second], it->first);
-                       
-               // make references for personality entries
-               uint32_t* personalityArray = (uint32_t*)&fHeaderContent[sectionHeader->personalityArraySectionOffset()];
-               for (std::map<ObjectFile::Atom*, unsigned int>::iterator it=fPersonalityIndexMap.begin(); it != fPersonalityIndexMap.end(); ++it) {
-                       uint32_t offset = (uint8_t*)&personalityArray[it->second-1] - fHeaderContent;
-                       fReferences.push_back(new WriterReference<A>(offset, A::kImageOffset32, it->first));
-               }
-
-               // build first level index and references
-               macho_unwind_info_section_header_index_entry<P>* indexTable = (macho_unwind_info_section_header_index_entry<P>*)&fHeaderContent[indexSectionOffset];
-               for (unsigned int i=0; i < secondLevelPageCount; ++i) {
-                       unsigned int reverseIndex = secondLevelPageCount - 1 - i;
-                       indexTable[i].set_functionOffset(0);
-                       indexTable[i].set_secondLevelPagesSectionOffset(secondLevelPagesStarts[reverseIndex]-fPagesContent+headerEndSectionOffset);
-                       indexTable[i].set_lsdaIndexArraySectionOffset(lsdaIndexOffsetMap[secondLevelFirstFuncs[reverseIndex]]+lsdaIndexArraySectionOffset); 
-                       uint32_t refOffset = (uint8_t*)&indexTable[i] - fHeaderContent;
-                       fReferences.push_back(new WriterReference<A>(refOffset, A::kImageOffset32, secondLevelFirstFuncs[reverseIndex]));
-               }
-               indexTable[secondLevelPageCount].set_functionOffset(0);
-               indexTable[secondLevelPageCount].set_secondLevelPagesSectionOffset(0);
-               indexTable[secondLevelPageCount].set_lsdaIndexArraySectionOffset(lsdaIndexArraySectionOffset+lsdaIndexArraySize); 
-               fReferences.push_back(new WriterReference<A>((uint8_t*)&indexTable[secondLevelPageCount] - fHeaderContent, A::kImageOffset32, 
-                                                                                                               fInfos.back().func, fInfos.back().func->getSize()+1));
-               
-               // build lsda references
-               uint32_t lsdaEntrySectionOffset = lsdaIndexArraySectionOffset;
-               for (typename std::vector<LSDAEntry>::iterator it = fLSDAIndex.begin(); it != fLSDAIndex.end(); ++it) {
-                       fReferences.push_back(new WriterReference<A>(lsdaEntrySectionOffset, A::kImageOffset32, it->func));
-                       fReferences.push_back(new WriterReference<A>(lsdaEntrySectionOffset+4, A::kImageOffset32, it->lsda, it->lsdaOffset));
-                       lsdaEntrySectionOffset += sizeof(unwind_info_section_header_lsda_index_entry);
-               }
-               
-               // make references for regular second level entries
-               for (typename std::vector<RegFixUp>::iterator it = fRegFixUps.begin(); it != fRegFixUps.end(); ++it) {
-                       uint32_t offset = (it->contentPointer - fPagesContent) + fHeaderSize;
-                       fReferences.push_back(new WriterReference<A>(offset, A::kImageOffset32, it->func));
-                       if ( it->fde != NULL )
-                               fReferences.push_back(new WriterReference<A>(offset+4, A::kSectionOffset24, it->fde));
-               }
-               // make references for compressed second level entries
-               for (typename std::vector<CompressedFixUp>::iterator it = fCompressedFixUps.begin(); it != fCompressedFixUps.end(); ++it) {
-                       uint32_t offset = (it->contentPointer - fPagesContent) + fHeaderSize;
-                       fReferences.push_back(new WriterReference<A>(offset, A::kPointerDiff24, it->func, 0, it->fromFunc, 0));
-               }
-               for (typename std::vector<CompressedEncodingFixUp>::iterator it = fCompressedEncodingFixUps.begin(); it != fCompressedEncodingFixUps.end(); ++it) {
-                       uint32_t offset = (it->contentPointer - fPagesContent) + fHeaderSize;
-                       fReferences.push_back(new WriterReference<A>(offset, A::kSectionOffset24, it->fde));
-               }
-                               
-               // update section record with new size
-               unwindSectionInfo->fSize = this->getSize();
-               
-               // alter alignment so this section lays out so second level tables are page aligned
-               if ( secondLevelPageCount > 2 )
-                       fAlignment = ObjectFile::Alignment(12, (unwindSectionInfo->fFileOffset - this->getSize()) % 4096);
-       }
-
-}
-
-
-
-
-template <typename A>
-void UnwindInfoAtom<A>::copyRawContent(uint8_t buffer[]) const
-{
-       memcpy(buffer, fHeaderContent, fHeaderSize);
-       memcpy(&buffer[fHeaderSize], fPagesContent, fPagesSize);
-}
-
-
-
-template <typename A>
-uint64_t LinkEditAtom<A>::getFileOffset() const
-{
-       return ((SectionInfo*)this->getSection())->fFileOffset + this->getSectionOffset();
-}
-
-
-template <typename A>
-uint64_t SectionRelocationsLinkEditAtom<A>::getSize() const
-{
-       return fWriter.fSectionRelocs.size() * sizeof(macho_relocation_info<P>);
-}
-
-template <typename A>
-void SectionRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
-{
-       memcpy(buffer, &fWriter.fSectionRelocs[0], this->getSize());
-}
-
-
-template <typename A>
-uint64_t LocalRelocationsLinkEditAtom<A>::getSize() const
-{
-       return fWriter.fInternalRelocs.size() * sizeof(macho_relocation_info<P>);
-}
-
-template <typename A>
-void LocalRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
-{
-       memcpy(buffer, &fWriter.fInternalRelocs[0], this->getSize());
-}
-
-
-
-template <typename A>
-uint64_t SymbolTableLinkEditAtom<A>::getSize() const
-{
-       return fWriter.fSymbolTableCount * sizeof(macho_nlist<P>);
-}
-
-template <typename A>
-void SymbolTableLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
-{
-       memcpy(buffer, fWriter.fSymbolTable, this->getSize());
-}
-
-template <typename A>
-uint64_t ExternalRelocationsLinkEditAtom<A>::getSize() const
-{
-       return fWriter.fExternalRelocs.size() * sizeof(macho_relocation_info<P>);
-}
-
-template <typename A>
-void ExternalRelocationsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
-{
-       std::sort(fWriter.fExternalRelocs.begin(), fWriter.fExternalRelocs.end(), ExternalRelocSorter<P>());
-       memcpy(buffer, &fWriter.fExternalRelocs[0], this->getSize());
-}
-
-
-
-template <typename A>
-uint64_t IndirectTableLinkEditAtom<A>::getSize() const
-{
-       return fTable.size() * sizeof(uint32_t);
-}
-
-template <typename A>
-void IndirectTableLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
-{
-       uint64_t size = this->getSize();
-       bzero(buffer, size);
-       const uint32_t indirectTableSize = fTable.size();
-       uint32_t* indirectTable = (uint32_t*)buffer;
-       for(std::vector<IndirectEntry>::const_iterator it = fTable.begin(); it != fTable.end(); ++it) {
-               if ( it->indirectIndex < indirectTableSize )
-                       A::P::E::set32(indirectTable[it->indirectIndex], it->symbolIndex);
-               else 
-                       throwf("malformed indirect table. size=%d, index=%d", indirectTableSize, it->indirectIndex);
-       }
-}
-
-
-
-template <typename A>
-uint64_t ModuleInfoLinkEditAtom<A>::getSize() const
-{
-       return fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents<P>) 
-                       + sizeof(macho_dylib_module<P>) 
-                       + this->getReferencesCount()*sizeof(uint32_t);
-}
-
-template <typename A>
-uint32_t ModuleInfoLinkEditAtom<A>::getTableOfContentsFileOffset() const
-{
-       return this->getFileOffset();
-}
-
-template <typename A>
-uint32_t ModuleInfoLinkEditAtom<A>::getModuleTableFileOffset() const
-{
-       return this->getFileOffset() + fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents<P>);
-}
-
-template <typename A>
-uint32_t ModuleInfoLinkEditAtom<A>::getReferencesFileOffset() const
-{
-       return this->getModuleTableFileOffset() + sizeof(macho_dylib_module<P>);
-}
-
-template <typename A>
-uint32_t ModuleInfoLinkEditAtom<A>::getReferencesCount() const
-{
-       return fWriter.fSymbolTableExportCount + fWriter.fSymbolTableImportCount;
-}
-
-template <typename A>
-void ModuleInfoLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
-{
-       uint64_t size = this->getSize();
-       bzero(buffer, size);
-       // create toc.  The symbols are already sorted, they are all in the smae module
-       macho_dylib_table_of_contents<P>* p = (macho_dylib_table_of_contents<P>*)buffer;
-       for(uint32_t i=0; i < fWriter.fSymbolTableExportCount; ++i, ++p) {
-               p->set_symbol_index(fWriter.fSymbolTableExportStartIndex+i);
-               p->set_module_index(0);
-       }
-       // create module table (one entry)
-       pint_t objcModuleSectionStart = 0;
-       pint_t objcModuleSectionSize = 0;
-       uint16_t numInits = 0;
-       uint16_t numTerms = 0;
-       std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
-       for (std::vector<SegmentInfo*>::iterator segit = segmentInfos.begin(); segit != segmentInfos.end(); ++segit) {
-               std::vector<SectionInfo*>& sectionInfos = (*segit)->fSections;
-               if ( strcmp((*segit)->fName, "__DATA") == 0 ) {
-                       for (std::vector<SectionInfo*>::iterator sectit = sectionInfos.begin(); sectit != sectionInfos.end(); ++sectit) {
-                               if ( strcmp((*sectit)->fSectionName, "__mod_init_func") == 0 ) 
-                                       numInits = (*sectit)->fSize / sizeof(typename A::P::uint_t);
-                               else if ( strcmp((*sectit)->fSectionName, "__mod_term_func") == 0 ) 
-                                       numTerms = (*sectit)->fSize / sizeof(typename A::P::uint_t);
-                       }
-               }
-               else if ( strcmp((*segit)->fName, "__OBJC") == 0 ) {
-                       for (std::vector<SectionInfo*>::iterator sectit = sectionInfos.begin(); sectit != sectionInfos.end(); ++sectit) {
-                               SectionInfo* sectInfo = (*sectit);
-                               if ( strcmp(sectInfo->fSectionName, "__module_info") == 0 ) {
-                                       objcModuleSectionStart = sectInfo->getBaseAddress();
-                                       objcModuleSectionSize  = sectInfo->fSize;
-                               }
-                       }
-               }
-       }
-       macho_dylib_module<P>* module = (macho_dylib_module<P>*)&buffer[fWriter.fSymbolTableExportCount*sizeof(macho_dylib_table_of_contents<P>)];
-       module->set_module_name(fModuleNameOffset);
-       module->set_iextdefsym(fWriter.fSymbolTableExportStartIndex);
-       module->set_nextdefsym(fWriter.fSymbolTableExportCount);
-       module->set_irefsym(0);
-       module->set_nrefsym(this->getReferencesCount());
-       module->set_ilocalsym(fWriter.fSymbolTableStabsStartIndex);
-       module->set_nlocalsym(fWriter.fSymbolTableStabsCount+fWriter.fSymbolTableLocalCount);
-       module->set_iextrel(0);
-       module->set_nextrel(fWriter.fExternalRelocs.size());
-       module->set_iinit_iterm(0,0);
-       module->set_ninit_nterm(numInits,numTerms);
-       module->set_objc_module_info_addr(objcModuleSectionStart);      
-       module->set_objc_module_info_size(objcModuleSectionSize);       
-       // create reference table
-       macho_dylib_reference<P>* ref = (macho_dylib_reference<P>*)((uint8_t*)module + sizeof(macho_dylib_module<P>));
-       for(uint32_t i=0; i < fWriter.fSymbolTableExportCount; ++i, ++ref) {
-               ref->set_isym(fWriter.fSymbolTableExportStartIndex+i);
-               ref->set_flags(REFERENCE_FLAG_DEFINED);
-       }
-       for(uint32_t i=0; i < fWriter.fSymbolTableImportCount; ++i, ++ref) {
-               ref->set_isym(fWriter.fSymbolTableImportStartIndex+i);
-               std::map<const ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fWriter.fStubsMap.find(fWriter.fImportedAtoms[i]);
-               if ( pos != fWriter.fStubsMap.end() )
-                       ref->set_flags(REFERENCE_FLAG_UNDEFINED_LAZY);
-               else
-                       ref->set_flags(REFERENCE_FLAG_UNDEFINED_NON_LAZY);
-       }
-}
-
-
-
-template <typename A>
-StringsLinkEditAtom<A>::StringsLinkEditAtom(Writer<A>& writer)
-       : LinkEditAtom<A>(writer), fCurrentBuffer(NULL), fCurrentBufferUsed(0)
-{
-       fCurrentBuffer = new char[kBufferSize];
-       // burn first byte of string pool (so zero is never a valid string offset)
-       fCurrentBuffer[fCurrentBufferUsed++] = ' ';
-       // make offset 1 always point to an empty string
-       fCurrentBuffer[fCurrentBufferUsed++] = '\0';
-}
-
-template <typename A>
-uint64_t StringsLinkEditAtom<A>::getSize() const
-{
-       // align size
-       return (kBufferSize * fFullBuffers.size() + fCurrentBufferUsed + sizeof(typename A::P::uint_t) - 1) & (-sizeof(typename A::P::uint_t));
-}
-
-template <typename A>
-void StringsLinkEditAtom<A>::copyRawContent(uint8_t buffer[]) const
-{
-       uint64_t offset = 0;
-       for (unsigned int i=0; i < fFullBuffers.size(); ++i) {
-               memcpy(&buffer[offset], fFullBuffers[i], kBufferSize);
-               offset += kBufferSize;
-       }
-       memcpy(&buffer[offset], fCurrentBuffer, fCurrentBufferUsed);
-       // zero fill end to align
-       offset += fCurrentBufferUsed;
-       while ( (offset % sizeof(typename A::P::uint_t)) != 0 )
-               buffer[offset++] = 0;
-}
-
-template <typename A>
-int32_t StringsLinkEditAtom<A>::add(const char* name)
-{
-       int32_t offset = kBufferSize * fFullBuffers.size() + fCurrentBufferUsed;
-       int lenNeeded = strlcpy(&fCurrentBuffer[fCurrentBufferUsed], name, kBufferSize-fCurrentBufferUsed)+1;
-       if ( (fCurrentBufferUsed+lenNeeded) < kBufferSize ) {
-               fCurrentBufferUsed += lenNeeded;
-       }
-       else {
-               int copied = kBufferSize-fCurrentBufferUsed-1;
-               // change trailing '\0' that strlcpy added to real char
-               fCurrentBuffer[kBufferSize-1] = name[copied];
-               // alloc next buffer
-               fFullBuffers.push_back(fCurrentBuffer);
-               fCurrentBuffer = new char[kBufferSize];
-               fCurrentBufferUsed = 0;
-               // append rest of string
-               this->add(&name[copied+1]);
-       }
-       return offset;
-}
-
-
-template <typename A>
-int32_t StringsLinkEditAtom<A>::addUnique(const char* name)
-{
-       StringToOffset::iterator pos = fUniqueStrings.find(name);
-       if ( pos != fUniqueStrings.end() ) {
-               return pos->second;
-       }
-       else {
-               int32_t offset = this->add(name);
-               fUniqueStrings[name] = offset;
-               return offset;
-       }
-}
-
-
-template <typename A>
-const char* StringsLinkEditAtom<A>::stringForIndex(int32_t index) const
-{
-       int32_t currentBufferStartIndex = kBufferSize * fFullBuffers.size();
-       int32_t maxIndex = currentBufferStartIndex + fCurrentBufferUsed;
-       // check for out of bounds
-       if ( index > maxIndex )
-               return "";
-       // check for index in fCurrentBuffer
-       if ( index > currentBufferStartIndex )
-               return &fCurrentBuffer[index-currentBufferStartIndex];
-       // otherwise index is in a full buffer
-       uint32_t fullBufferIndex = index/kBufferSize;
-       return &fFullBuffers[fullBufferIndex][index-(kBufferSize*fullBufferIndex)];
-}
-
-
-
-template <typename A>
-BranchIslandAtom<A>::BranchIslandAtom(Writer<A>& writer, const char* name, int islandRegion, ObjectFile::Atom& target, 
-                                                                                       ObjectFile::Atom& finalTarget, uint32_t finalTargetOffset)
- : WriterAtom<A>(writer, Segment::fgTextSegment), fTarget(target), fFinalTarget(finalTarget), fFinalTargetOffset(finalTargetOffset)
-{
-       if ( finalTargetOffset == 0 ) {
-               if ( islandRegion == 0 )
-                       asprintf((char**)&fName, "%s$island", name);
-               else
-                       asprintf((char**)&fName, "%s$island$%d", name, islandRegion+1);
-       }
-       else {
-               asprintf((char**)&fName, "%s_plus_%d$island$%d", name, finalTargetOffset, islandRegion);
-       }
-       
-       if ( finalTarget.isThumb() ) {
-               if ( writer.fOptions.preferSubArchitecture() && writer.fOptions.subArchitecture() == CPU_SUBTYPE_ARM_V7 ) {
-                       fIslandKind = kBranchIslandToThumb2;
-               }
-               else {
-                       if ( writer.fSlideable )
-                               fIslandKind = kBranchIslandToThumb1;
-                       else
-                               fIslandKind = kBranchIslandNoPicToThumb1;
-               }
-       }
-       else {
-               fIslandKind = kBranchIslandToARM;
-       }
-}
-
-
-template <>
-void BranchIslandAtom<ppc>::copyRawContent(uint8_t buffer[]) const
-{
-       int64_t displacement;
-       const int64_t bl_sixteenMegLimit = 0x00FFFFFF;
-       if ( fTarget.getContentType() == ObjectFile::Atom::kBranchIsland ) {
-               displacement = getFinalTargetAdress() - this->getAddress();
-               if ( (displacement > bl_sixteenMegLimit) && (displacement < (-bl_sixteenMegLimit)) ) {
-                       displacement = fTarget.getAddress() - this->getAddress();
-               }
-       }
-       else {
-               displacement = fTarget.getAddress() + fFinalTargetOffset - this->getAddress();
-       }
-       int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
-       OSWriteBigInt32(buffer, 0, branchInstruction);
-}
-
-template <>
-void BranchIslandAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
-{
-       int64_t displacement;
-       const int64_t bl_sixteenMegLimit = 0x00FFFFFF;
-       if ( fTarget.getContentType() == ObjectFile::Atom::kBranchIsland ) {
-               displacement = getFinalTargetAdress() - this->getAddress();
-               if ( (displacement > bl_sixteenMegLimit) && (displacement < (-bl_sixteenMegLimit)) ) {
-                       displacement = fTarget.getAddress() - this->getAddress();
-               }
-       }
-       else {
-               displacement = fTarget.getAddress() + fFinalTargetOffset - this->getAddress();
-       }
-       int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
-       OSWriteBigInt32(buffer, 0, branchInstruction);
-}
-
-template <>
-void BranchIslandAtom<arm>::copyRawContent(uint8_t buffer[]) const
-{
-       const bool log = false;
-       switch ( fIslandKind ) {
-               case kBranchIslandToARM:
-                       {
-                       int64_t displacement;
-                       // an ARM branch can branch farther than a thumb branch.  The branch
-                       // island generation was conservative and put islands every thumb
-                       // branch distance apart.  Check to see if this is a an island
-                       // hopping branch that could be optimized to go directly to target.
-                       if ( fTarget.getContentType() == ObjectFile::Atom::kBranchIsland ) {
-                               displacement = getFinalTargetAdress() - this->getAddress() - 8;
-                               if ( (displacement < 33554428LL) && (displacement > (-33554432LL)) ) {
-                                       // can skip branch island and jump straight to target
-                                       if (log) fprintf(stderr, "%s: optimized jump to final target at 0x%08llX, thisAddr=0x%08llX\n", fName, getFinalTargetAdress(), this->getAddress());
-                               }
-                               else {
-                                       // ultimate target is too far, jump to island
-                                       displacement = fTarget.getAddress() - this->getAddress() - 8;
-                                       if (log) fprintf(stderr, "%s: jump to branch island at 0x%08llX\n", fName, fTarget.getAddress());
-                               }
-                       }
-                       else {
-                               // target of island is ultimate target
-                               displacement = fTarget.getAddress() + fFinalTargetOffset - this->getAddress() - 8;
-                               if (log) fprintf(stderr, "%s: jump to target at 0x%08llX\n", fName, fTarget.getAddress());
-                       }
-                       uint32_t imm24 = (displacement >> 2) & 0x00FFFFFF;
-                       int32_t branchInstruction = 0xEA000000 | imm24;
-                       OSWriteLittleInt32(buffer, 0, branchInstruction);
-                       }
-                       break;
-               case kBranchIslandToThumb2:
-                       {
-                       int64_t displacement;
-                       // an ARM branch can branch farther than a thumb branch.  The branch
-                       // island generation was conservative and put islands every thumb
-                       // branch distance apart.  Check to see if this is a an island
-                       // hopping branch that could be optimized to go directly to target.
-                       if ( fTarget.getContentType() == ObjectFile::Atom::kBranchIsland ) {
-                               displacement = getFinalTargetAdress() - this->getAddress() - 4;
-                               if ( (displacement < 16777214) && (displacement > (-16777216LL)) ) {
-                                       // can skip branch island and jump straight to target
-                                       if (log) fprintf(stderr, "%s: optimized jump to final target at 0x%08llX, thisAddr=0x%08llX\n", fName, getFinalTargetAdress(), this->getAddress());
-                               }
-                               else {
-                                       // ultimate target is too far, jump to island
-                                       displacement = fTarget.getAddress() - this->getAddress() - 4;
-                                       if (log) fprintf(stderr, "%s: jump to branch island at 0x%08llX\n", fName, fTarget.getAddress());
-                               }
-                       }
-                       else {
-                               // target of island is ultimate target
-                               displacement = fTarget.getAddress() + fFinalTargetOffset - this->getAddress() - 4;
-                               if (log) fprintf(stderr, "%s: jump to target at 0x%08llX\n", fName, fTarget.getAddress());
-                       }
-                       if ( (displacement > 16777214) || (displacement < (-16777216LL)) ) {
-                               throwf("internal branch island error: thumb2 b/bx out of range (%lld max is +/-16M) from %s to %s in %s",
-                                               displacement, this->getDisplayName(), 
-                                               fTarget.getDisplayName(), fTarget.getFile()->getPath());
-                       }
-                       // The instruction is really two instructions:
-                       // The lower 16 bits are the first instruction, which contains the high
-                       //   11 bits of the displacement.
-                       // The upper 16 bits are the second instruction, which contains the low
-                       //   11 bits of the displacement, as well as differentiating bl and blx.
-                       uint32_t s = (uint32_t)(displacement >> 24) & 0x1;
-                       uint32_t i1 = (uint32_t)(displacement >> 23) & 0x1;
-                       uint32_t i2 = (uint32_t)(displacement >> 22) & 0x1;
-                       uint32_t imm10 = (uint32_t)(displacement >> 12) & 0x3FF;
-                       uint32_t imm11 = (uint32_t)(displacement >> 1) & 0x7FF;
-                       uint32_t j1 = (i1 == s);
-                       uint32_t j2 = (i2 == s);
-                       uint32_t opcode = 0x9000F000;
-                       uint32_t nextDisp = (j1 << 13) | (j2 << 11) | imm11;
-                       uint32_t firstDisp = (s << 10) | imm10;
-                       uint32_t newInstruction = opcode | (nextDisp << 16) | firstDisp;
-                       //warning("s=%d, j1=%d, j2=%d, imm10=0x%0X, imm11=0x%0X, opcode=0x%08X, first=0x%04X, next=0x%04X, new=0x%08X, disp=0x%llX for %s to %s\n",
-                       //      s, j1, j2, imm10, imm11, opcode, firstDisp, nextDisp, newInstruction, displacement, inAtom->getDisplayName(), ref->getTarget().getDisplayName());
-                       OSWriteLittleInt32(buffer, 0, newInstruction);
-                       }
-                       break;
-               case kBranchIslandToThumb1:
-                       {
-                       // There is no large displacement thumb1 branch instruction.
-                       // Instead use ARM instructions that can jump to thumb.
-                       // we use a 32-bit displacement, so we can directly jump to target which means no island hopping
-                       int64_t displacement = getFinalTargetAdress() - (this->getAddress() + 12);
-                       if ( fFinalTarget.isThumb() )
-                               displacement |= 1;
-                       if (log) fprintf(stderr, "%s: 4 ARM instruction jump to final target at 0x%08llX\n", fName, getFinalTargetAdress());
-                       OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc004); //      ldr  ip, pc + 4
-                       OSWriteLittleInt32(&buffer[ 4], 0, 0xe08fc00c); //      add      ip, pc, ip
-                       OSWriteLittleInt32(&buffer[ 8], 0, 0xe12fff1c); //      bx       ip
-                       OSWriteLittleInt32(&buffer[12], 0, displacement);       //      .long target-this               
-                       }
-                       break;
-               case kBranchIslandNoPicToThumb1:
-                       {
-                       // There is no large displacement thumb1 branch instruction.
-                       // Instead use ARM instructions that can jump to thumb.
-                       // we use a 32-bit displacement, so we can directly jump to target which means no island hopping
-                       uint32_t targetAddr = getFinalTargetAdress();
-                       if ( fFinalTarget.isThumb() )
-                               targetAddr |= 1;
-                       if (log) fprintf(stderr, "%s: 2 ARM instruction jump to final target at 0x%08llX\n", fName, getFinalTargetAdress());
-                       OSWriteLittleInt32(&buffer[0], 0, 0xe51ff004);  //      ldr     pc, [pc, #-4]
-                       OSWriteLittleInt32(&buffer[4], 0, targetAddr);  //      .long target-this               
-                       }
-                       break;  
-       };
-}
-
-template <>
-uint64_t BranchIslandAtom<ppc>::getSize() const
-{
-       return 4;
-}
-
-template <>
-uint64_t BranchIslandAtom<ppc64>::getSize() const
-{
-       return 4;
-}
-
-template <>
-uint64_t BranchIslandAtom<arm>::getSize() const
-{
-       switch ( fIslandKind ) {
-               case kBranchIslandToARM:
-                       return 4;
-               case kBranchIslandToThumb1:
-                       return 16;
-               case kBranchIslandToThumb2:
-                       return 4;
-               case kBranchIslandNoPicToThumb1:
-                       return 8;
-       };
-       throw "internal error: no ARM branch island kind";
-}
-
-
-
-template <typename A>
-uint64_t SegmentSplitInfoLoadCommandsAtom<A>::getSize() const
-{
-       if ( fWriter.fSplitCodeToDataContentAtom->canEncode() )
-               return this->alignedSize(sizeof(macho_linkedit_data_command<P>));
-       else
-               return 0;       // a zero size causes the load command to be suppressed
-}
-
-template <typename A>
-void SegmentSplitInfoLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
-{
-       uint64_t size = this->getSize();
-       if ( size > 0 ) {
-               bzero(buffer, size);
-               macho_linkedit_data_command<P>* cmd = (macho_linkedit_data_command<P>*)buffer;
-               cmd->set_cmd(LC_SEGMENT_SPLIT_INFO);
-               cmd->set_cmdsize(size);
-               cmd->set_dataoff(fWriter.fSplitCodeToDataContentAtom->getFileOffset());
-               cmd->set_datasize(fWriter.fSplitCodeToDataContentAtom->getSize());
-       }
-}
-
-
-template <typename A>
-uint64_t SegmentSplitInfoContentAtom<A>::getSize() const
-{
-       return fEncodedData.size();
-}
-
-template <typename A>
-void SegmentSplitInfoContentAtom<A>::copyRawContent(uint8_t buffer[]) const
-{
-       memcpy(buffer, &fEncodedData[0], fEncodedData.size());
-}
-
-
-template <typename A>
-void SegmentSplitInfoContentAtom<A>::uleb128EncodeAddresses(const std::vector<SegmentSplitInfoContentAtom<A>::AtomAndOffset>& locations)
-{
-       pint_t addr = fWriter.fOptions.baseAddress();
-       for(typename std::vector<AtomAndOffset>::const_iterator it = locations.begin(); it != locations.end(); ++it) {
-               pint_t nextAddr = it->atom->getAddress() + it->offset;
-               //fprintf(stderr, "\t0x%0llX\n", (uint64_t)nextAddr);
-               uint64_t delta = nextAddr - addr;
-               if ( delta == 0 ) 
-                       throw "double split seg info for same address";
-               // uleb128 encode
-               uint8_t byte;
-               do {
-                       byte = delta & 0x7F;
-                       delta &= ~0x7F;
-                       if ( delta != 0 )
-                               byte |= 0x80;
-                       fEncodedData.push_back(byte);
-                       delta = delta >> 7;
-               } 
-               while( byte >= 0x80 );
-               addr = nextAddr;
-       }
-}
-
-template <typename A>
-void SegmentSplitInfoContentAtom<A>::encode()
-{
-       if ( ! fCantEncode ) {
-               fEncodedData.reserve(8192);
-               
-               if ( fKind1Locations.size() != 0 ) {
-                       fEncodedData.push_back(1);
-                       //fprintf(stderr, "type 1:\n");
-                       this->uleb128EncodeAddresses(fKind1Locations);
-                       fEncodedData.push_back(0);
-               }
-               
-               if ( fKind2Locations.size() != 0 ) {
-                       fEncodedData.push_back(2);
-                       //fprintf(stderr, "type 2:\n");
-                       this->uleb128EncodeAddresses(fKind2Locations);
-                       fEncodedData.push_back(0);
-               }
-               
-               if ( fKind3Locations.size() != 0 ) {
-                       fEncodedData.push_back(3);
-                       //fprintf(stderr, "type 3:\n");
-                       this->uleb128EncodeAddresses(fKind3Locations);
-                       fEncodedData.push_back(0);
-               }
-               
-               if ( fKind4Locations.size() != 0 ) {
-                       fEncodedData.push_back(4);
-                       //fprintf(stderr, "type 4:\n");
-                       this->uleb128EncodeAddresses(fKind4Locations);
-                       fEncodedData.push_back(0);
-               }
-               
-               // always add zero byte to mark end
-               fEncodedData.push_back(0);
-
-               // add zeros to end to align size
-               while ( (fEncodedData.size() % sizeof(pint_t)) != 0 )
-                       fEncodedData.push_back(0);
-       }
-}
-
-
-template <typename A>
-ObjCInfoAtom<A>::ObjCInfoAtom(Writer<A>& writer, ObjectFile::Reader::ObjcConstraint objcConstraint, 
-                                                                       bool objcReplacementClasses, bool abi2override)
-       : WriterAtom<A>(writer, getInfoSegment(abi2override)), fAbi2override(abi2override)
-{
-       fContent[0] = 0;
-       uint32_t value = 0;
-       //      struct objc_image_info  {
-       //              uint32_t        version;        // initially 0
-       //              uint32_t        flags;
-       //      };
-       // #define OBJC_IMAGE_SUPPORTS_GC   2
-       // #define OBJC_IMAGE_GC_ONLY       4
-       //
-       if ( objcReplacementClasses ) 
-               value = 1;
-       switch ( objcConstraint ) {
-               case ObjectFile::Reader::kObjcNone:
-               case ObjectFile::Reader::kObjcRetainRelease:
-                       break;
-               case ObjectFile::Reader::kObjcRetainReleaseOrGC:
-                       value |= 2;
-                       break;
-               case ObjectFile::Reader::kObjcGC:
-                       value |= 6;
-                       break;
-       }
-       A::P::E::set32(fContent[1], value);
-}
-
-template <typename A>
-void ObjCInfoAtom<A>::copyRawContent(uint8_t buffer[]) const
-{
-       memcpy(buffer, &fContent[0], 8);
-}
-
-
-// objc info section is in a different segment and section for 32 vs 64 bit runtimes
-template <> const char* ObjCInfoAtom<ppc>::getSectionName()    const { return "__image_info"; }
-template <> const char* ObjCInfoAtom<x86>::getSectionName()    const { return fAbi2override ? "__objc_imageinfo" : "__image_info"; }
-template <> const char* ObjCInfoAtom<arm>::getSectionName()    const { return "__objc_imageinfo"; }
-template <> const char* ObjCInfoAtom<ppc64>::getSectionName()  const { return "__objc_imageinfo"; }
-template <> const char* ObjCInfoAtom<x86_64>::getSectionName() const { return "__objc_imageinfo"; }
-
-template <> Segment& ObjCInfoAtom<ppc>::getInfoSegment(bool abi2override)    const { return Segment::fgObjCSegment; }
-template <> Segment& ObjCInfoAtom<x86>::getInfoSegment(bool abi2override)    const { return abi2override ? Segment::fgDataSegment : Segment::fgObjCSegment; }
-template <> Segment& ObjCInfoAtom<ppc64>::getInfoSegment(bool abi2override)  const { return Segment::fgDataSegment; }
-template <> Segment& ObjCInfoAtom<x86_64>::getInfoSegment(bool abi2override) const { return Segment::fgDataSegment; }
-template <> Segment& ObjCInfoAtom<arm>::getInfoSegment(bool abi2override)    const { return Segment::fgDataSegment; }
-
-
-
-
-template <typename A>
-void DyldInfoLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
-{
-       // build LC_DYLD_INFO command
-       macho_dyld_info_command<P>*  cmd = (macho_dyld_info_command<P>*)buffer;
-       bzero(cmd, sizeof(macho_dyld_info_command<P>));
-       
-       cmd->set_cmd( fWriter.fOptions.makeClassicDyldInfo() ? LC_DYLD_INFO : LC_DYLD_INFO_ONLY);
-       cmd->set_cmdsize(sizeof(macho_dyld_info_command<P>));
-       if ( (fWriter.fCompressedRebaseInfoAtom != NULL) && (fWriter.fCompressedRebaseInfoAtom->getSize() != 0) ) {
-               cmd->set_rebase_off(fWriter.fCompressedRebaseInfoAtom->getFileOffset());
-               cmd->set_rebase_size(fWriter.fCompressedRebaseInfoAtom->getSize());
-       }
-       if ( (fWriter.fCompressedBindingInfoAtom != NULL) && (fWriter.fCompressedBindingInfoAtom->getSize() != 0) ) {
-               cmd->set_bind_off(fWriter.fCompressedBindingInfoAtom->getFileOffset());
-               cmd->set_bind_size(fWriter.fCompressedBindingInfoAtom->getSize());
-       }
-       if ( (fWriter.fCompressedWeakBindingInfoAtom != NULL) && (fWriter.fCompressedWeakBindingInfoAtom->getSize() != 0) ) {
-               cmd->set_weak_bind_off(fWriter.fCompressedWeakBindingInfoAtom->getFileOffset());
-               cmd->set_weak_bind_size(fWriter.fCompressedWeakBindingInfoAtom->getSize());
-       }
-       if ( (fWriter.fCompressedLazyBindingInfoAtom != NULL) && (fWriter.fCompressedLazyBindingInfoAtom->getSize() != 0) ) {
-               cmd->set_lazy_bind_off(fWriter.fCompressedLazyBindingInfoAtom->getFileOffset());
-               cmd->set_lazy_bind_size(fWriter.fCompressedLazyBindingInfoAtom->getSize());
-       }
-       if ( (fWriter.fCompressedExportInfoAtom != NULL) && (fWriter.fCompressedExportInfoAtom->getSize() != 0) ) {
-               cmd->set_export_off(fWriter.fCompressedExportInfoAtom->getFileOffset());
-               cmd->set_export_size(fWriter.fCompressedExportInfoAtom->getSize());
-       }
-}
-
-
-struct rebase_tmp
-{
-       rebase_tmp(uint8_t op, uint64_t p1, uint64_t p2=0) : opcode(op), operand1(p1), operand2(p2) {}
-       uint8_t         opcode;
-       uint64_t        operand1;
-       uint64_t        operand2;
-};
-
-
-template <typename A>
-void CompressedRebaseInfoLinkEditAtom<A>::encode()
-{
-       // sort rebase info by type, then address
-       const std::vector<SegmentInfo*>& segments = fWriter.fSegmentInfos;
-       std::vector<RebaseInfo>& info = fWriter.fRebaseInfo;
-       std::sort(info.begin(), info.end());
-       
-       // convert to temp encoding that can be more easily optimized
-       std::vector<rebase_tmp> mid;
-       const SegmentInfo* currentSegment = NULL;
-       unsigned int segIndex = 0;
-       uint8_t type = 0;
-       uint64_t address = (uint64_t)(-1);
-       for (std::vector<RebaseInfo>::iterator it = info.begin(); it != info.end(); ++it) {
-               if ( type != it->fType ) {
-                       mid.push_back(rebase_tmp(REBASE_OPCODE_SET_TYPE_IMM, it->fType));
-                       type = it->fType;
-               }
-               if ( address != it->fAddress ) {
-                       if ( (currentSegment == NULL) || (it->fAddress < currentSegment->fBaseAddress) 
-                                       || ((currentSegment->fBaseAddress+currentSegment->fSize) <= it->fAddress) ) {
-                               segIndex = 0;
-                               for (std::vector<SegmentInfo*>::const_iterator segit = segments.begin(); segit != segments.end(); ++segit) {
-                                       if ( ((*segit)->fBaseAddress <= it->fAddress) && (it->fAddress < ((*segit)->fBaseAddress+(*segit)->fSize)) ) {
-                                               currentSegment = *segit;
-                                               break;
-                                       }
-                                       ++segIndex;
-                               }
-                               mid.push_back(rebase_tmp(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, segIndex, it->fAddress - currentSegment->fBaseAddress));
-                       }
-                       else {
-                               mid.push_back(rebase_tmp(REBASE_OPCODE_ADD_ADDR_ULEB, it->fAddress-address));
-                       }
-                       address = it->fAddress;
-               }
-               mid.push_back(rebase_tmp(REBASE_OPCODE_DO_REBASE_ULEB_TIMES, 1));
-               address += sizeof(pint_t);
-       }
-       mid.push_back(rebase_tmp(REBASE_OPCODE_DONE, 0));
-
-       // optimize phase 1, compress packed runs of pointers
-       rebase_tmp* dst = &mid[0];
-       for (const rebase_tmp* src = &mid[0]; src->opcode != REBASE_OPCODE_DONE; ++src) {
-               if ( (src->opcode == REBASE_OPCODE_DO_REBASE_ULEB_TIMES) && (src->operand1 == 1) ) {
-                       *dst = *src++;
-                       while (src->opcode == REBASE_OPCODE_DO_REBASE_ULEB_TIMES ) {
-                               dst->operand1 += src->operand1;
-                               ++src;
-                       }
-                       --src;
-                       ++dst;
-               }
-               else {
-                       *dst++ = *src;
-               }
-       }
-       dst->opcode = REBASE_OPCODE_DONE;
-
-       // optimize phase 2, combine rebase/add pairs
-       dst = &mid[0];
-       for (const rebase_tmp* src = &mid[0]; src->opcode != REBASE_OPCODE_DONE; ++src) {
-               if ( (src->opcode == REBASE_OPCODE_DO_REBASE_ULEB_TIMES) 
-                               && (src->operand1 == 1) 
-                               && (src[1].opcode == REBASE_OPCODE_ADD_ADDR_ULEB)) {
-                       dst->opcode = REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB;
-                       dst->operand1 = src[1].operand1;
-                       ++src;
-                       ++dst;
-               }
-               else {
-                       *dst++ = *src;
-               }
-       }
-       dst->opcode = REBASE_OPCODE_DONE;
-       
-       // optimize phase 3, compress packed runs of REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB with
-       // same addr delta into one REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
-       dst = &mid[0];
-       for (const rebase_tmp* src = &mid[0]; src->opcode != REBASE_OPCODE_DONE; ++src) {
-               uint64_t delta = src->operand1;
-               if ( (src->opcode == REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB) 
-                               && (src[1].opcode == REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB) 
-                               && (src[2].opcode == REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB) 
-                               && (src[1].operand1 == delta) 
-                               && (src[2].operand1 == delta) ) {
-                       // found at least three in a row, this is worth compressing
-                       dst->opcode = REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB;
-                       dst->operand1 = 1;
-                       dst->operand2 = delta;
-                       ++src;
-                       while ( (src->opcode == REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB)
-                                       && (src->operand1 == delta) ) {
-                               dst->operand1++;
-                               ++src;
-                       }
-                       --src;
-                       ++dst;
-               }
-               else {
-                       *dst++ = *src;
-               }
-       }
-       dst->opcode = REBASE_OPCODE_DONE;
-       
-       // optimize phase 4, use immediate encodings
-       for (rebase_tmp* p = &mid[0]; p->opcode != REBASE_OPCODE_DONE; ++p) {
-               if ( (p->opcode == REBASE_OPCODE_ADD_ADDR_ULEB) 
-                       && (p->operand1 < (15*sizeof(pint_t)))
-                       && ((p->operand1 % sizeof(pint_t)) == 0) ) {
-                       p->opcode = REBASE_OPCODE_ADD_ADDR_IMM_SCALED;
-                       p->operand1 = p->operand1/sizeof(pint_t);
-               }
-               else if ( (p->opcode == REBASE_OPCODE_DO_REBASE_ULEB_TIMES) && (p->operand1 < 15) ) {
-                       p->opcode = REBASE_OPCODE_DO_REBASE_IMM_TIMES;
-               }
-       }
-
-       // convert to compressed encoding
-       const static bool log = false;
-       fEncodedData.reserve(info.size()*2);
-       bool done = false;
-       for (std::vector<rebase_tmp>::iterator it = mid.begin(); !done && it != mid.end() ; ++it) {
-               switch ( it->opcode ) {
-                       case REBASE_OPCODE_DONE:
-                               if ( log ) fprintf(stderr, "REBASE_OPCODE_DONE()\n");
-                               done = true;
-                               break;
-                       case REBASE_OPCODE_SET_TYPE_IMM:
-                               if ( log ) fprintf(stderr, "REBASE_OPCODE_SET_TYPE_IMM(%lld)\n", it->operand1);
-                               fEncodedData.append_byte(REBASE_OPCODE_SET_TYPE_IMM | it->operand1);
-                               break;
-                       case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
-                               if ( log ) fprintf(stderr, "REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%lld, 0x%llX)\n", it->operand1, it->operand2);
-                               fEncodedData.append_byte(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | it->operand1);
-                               fEncodedData.append_uleb128(it->operand2);
-                               break;
-                       case REBASE_OPCODE_ADD_ADDR_ULEB:
-                               if ( log ) fprintf(stderr, "REBASE_OPCODE_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
-                               fEncodedData.append_byte(REBASE_OPCODE_ADD_ADDR_ULEB);
-                               fEncodedData.append_uleb128(it->operand1);
-                               break;
-                       case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
-                               if ( log ) fprintf(stderr, "REBASE_OPCODE_ADD_ADDR_IMM_SCALED(%lld=0x%llX)\n", it->operand1, it->operand1*sizeof(pint_t));
-                               fEncodedData.append_byte(REBASE_OPCODE_ADD_ADDR_IMM_SCALED | it->operand1 );
-                               break;
-                       case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
-                               if ( log ) fprintf(stderr, "REBASE_OPCODE_DO_REBASE_IMM_TIMES(%lld)\n", it->operand1);
-                               fEncodedData.append_byte(REBASE_OPCODE_DO_REBASE_IMM_TIMES | it->operand1);
-                               break;
-                       case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
-                               if ( log ) fprintf(stderr, "REBASE_OPCODE_DO_REBASE_ULEB_TIMES(%lld)\n", it->operand1);
-                               fEncodedData.append_byte(REBASE_OPCODE_DO_REBASE_ULEB_TIMES);
-                               fEncodedData.append_uleb128(it->operand1);
-                               break;
-                       case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
-                               if ( log ) fprintf(stderr, "REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
-                               fEncodedData.append_byte(REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB);
-                               fEncodedData.append_uleb128(it->operand1);
-                               break;
-                       case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
-                               if ( log ) fprintf(stderr, "REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB(%lld, %lld)\n", it->operand1, it->operand2);
-                               fEncodedData.append_byte(REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB);
-                               fEncodedData.append_uleb128(it->operand1);
-                               fEncodedData.append_uleb128(it->operand2);
-                               break;
-               }
-       }
-       
-               
-       // align to pointer size
-       fEncodedData.pad_to_size(sizeof(pint_t));
-
-       if (log) fprintf(stderr, "total rebase info size = %ld\n", fEncodedData.size());
-}
-
-
-struct binding_tmp
-{
-       binding_tmp(uint8_t op, uint64_t p1, uint64_t p2=0, const char* s=NULL) 
-               : opcode(op), operand1(p1), operand2(p2), name(s) {}
-       uint8_t         opcode;
-       uint64_t        operand1;
-       uint64_t        operand2;
-       const char*     name;
-};
-
-
-
-template <typename A>
-void CompressedBindingInfoLinkEditAtom<A>::encode()
-{
-       // sort by library, symbol, type, then address
-       const std::vector<SegmentInfo*>& segments = fWriter.fSegmentInfos;
-       std::vector<BindingInfo>& info = fWriter.fBindingInfo;
-       std::sort(info.begin(), info.end());
-       
-       // convert to temp encoding that can be more easily optimized
-       std::vector<binding_tmp> mid;
-       const SegmentInfo* currentSegment = NULL;
-       unsigned int segIndex = 0;
-       int ordinal = 0x80000000;
-       const char* symbolName = NULL;
-       uint8_t type = 0;
-       uint64_t address = (uint64_t)(-1);
-       int64_t addend = 0;
-       for (std::vector<BindingInfo>::iterator it = info.begin(); it != info.end(); ++it) {
-               if ( ordinal != it->fLibraryOrdinal ) {
-                       if ( it->fLibraryOrdinal <= 0 ) {
-                               // special lookups are encoded as negative numbers in BindingInfo
-                               mid.push_back(binding_tmp(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM, it->fLibraryOrdinal));
-                       }
-                       else {
-                               mid.push_back(binding_tmp(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB, it->fLibraryOrdinal));
-                       }
-                       ordinal = it->fLibraryOrdinal;
-               }
-               if ( symbolName != it->fSymbolName ) {
-                       mid.push_back(binding_tmp(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM, it->fFlags, 0, it->fSymbolName));
-                       symbolName = it->fSymbolName;
-               }
-               if ( type != it->fType ) {
-                       mid.push_back(binding_tmp(BIND_OPCODE_SET_TYPE_IMM, it->fType));
-                       type = it->fType;
-               }
-               if ( address != it->fAddress ) {
-                       if ( (currentSegment == NULL) || (it->fAddress < currentSegment->fBaseAddress) 
-                                       || ((currentSegment->fBaseAddress+currentSegment->fSize) <=it->fAddress) 
-                                       || (it->fAddress < address) ) {
-                               segIndex = 0;
-                               for (std::vector<SegmentInfo*>::const_iterator segit = segments.begin(); segit != segments.end(); ++segit) {
-                                       if ( ((*segit)->fBaseAddress <= it->fAddress) && (it->fAddress < ((*segit)->fBaseAddress+(*segit)->fSize)) ) {
-                                               currentSegment = *segit;
-                                               break;
-                                       }
-                                       ++segIndex;
-                               }
-                               mid.push_back(binding_tmp(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, segIndex, it->fAddress - currentSegment->fBaseAddress));
-                       }
-                       else {
-                               mid.push_back(binding_tmp(BIND_OPCODE_ADD_ADDR_ULEB, it->fAddress-address));
-                       }
-                       address = it->fAddress;
-               }
-               if ( addend != it->fAddend ) {
-                       mid.push_back(binding_tmp(BIND_OPCODE_SET_ADDEND_SLEB, it->fAddend));
-                       addend = it->fAddend;
-               }
-               mid.push_back(binding_tmp(BIND_OPCODE_DO_BIND, 0));
-               address += sizeof(pint_t);
-       }
-       mid.push_back(binding_tmp(BIND_OPCODE_DONE, 0));
-
-
-       // optimize phase 1, combine bind/add pairs
-       binding_tmp* dst = &mid[0];
-       for (const binding_tmp* src = &mid[0]; src->opcode != BIND_OPCODE_DONE; ++src) {
-               if ( (src->opcode == BIND_OPCODE_DO_BIND) 
-                               && (src[1].opcode == BIND_OPCODE_ADD_ADDR_ULEB) ) {
-                       dst->opcode = BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB;
-                       dst->operand1 = src[1].operand1;
-                       ++src;
-                       ++dst;
-               }
-               else {
-                       *dst++ = *src;
-               }
-       }
-       dst->opcode = BIND_OPCODE_DONE;
-
-       // optimize phase 2, compress packed runs of BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB with
-       // same addr delta into one BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
-       dst = &mid[0];
-       for (const binding_tmp* src = &mid[0]; src->opcode != BIND_OPCODE_DONE; ++src) {
-               uint64_t delta = src->operand1;
-               if ( (src->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB) 
-                               && (src[1].opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB) 
-                               && (src[1].operand1 == delta) ) {
-                       // found at least two in a row, this is worth compressing
-                       dst->opcode = BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB;
-                       dst->operand1 = 1;
-                       dst->operand2 = delta;
-                       ++src;
-                       while ( (src->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
-                                       && (src->operand1 == delta) ) {
-                               dst->operand1++;
-                               ++src;
-                       }
-                       --src;
-                       ++dst;
-               }
-               else {
-                       *dst++ = *src;
-               }
-       }
-       dst->opcode = BIND_OPCODE_DONE;
-       
-       // optimize phase 3, use immediate encodings
-       for (binding_tmp* p = &mid[0]; p->opcode != REBASE_OPCODE_DONE; ++p) {
-               if ( (p->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB) 
-                       && (p->operand1 < (15*sizeof(pint_t)))
-                       && ((p->operand1 % sizeof(pint_t)) == 0) ) {
-                       p->opcode = BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED;
-                       p->operand1 = p->operand1/sizeof(pint_t);
-               }
-               else if ( (p->opcode == BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB) && (p->operand1 <= 15) ) {
-                       p->opcode = BIND_OPCODE_SET_DYLIB_ORDINAL_IMM;
-               }
-       }       
-       dst->opcode = BIND_OPCODE_DONE;
-
-       // convert to compressed encoding
-       const static bool log = false;
-       fEncodedData.reserve(info.size()*2);
-       bool done = false;
-       for (std::vector<binding_tmp>::iterator it = mid.begin(); !done && it != mid.end() ; ++it) {
-               switch ( it->opcode ) {
-                       case BIND_OPCODE_DONE:
-                               if ( log ) fprintf(stderr, "BIND_OPCODE_DONE()\n");
-                               done = true;
-                               break;
-                       case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
-                               if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%lld)\n", it->operand1);
-                               fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | it->operand1);
-                               break;
-                       case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
-                               if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%lld)\n", it->operand1);
-                               fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
-                               fEncodedData.append_uleb128(it->operand1);
-                               break;
-                       case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
-                               if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%lld)\n", it->operand1);
-                               fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | (it->operand1 & BIND_IMMEDIATE_MASK));
-                               break;
-                       case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
-                               if ( log ) fprintf(stderr, "BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%0llX, %s)\n", it->operand1, it->name);
-                               fEncodedData.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | it->operand1);
-                               fEncodedData.append_string(it->name);
-                               break;
-                       case BIND_OPCODE_SET_TYPE_IMM:
-                               if ( log ) fprintf(stderr, "BIND_OPCODE_SET_TYPE_IMM(%lld)\n", it->operand1);
-                               fEncodedData.append_byte(BIND_OPCODE_SET_TYPE_IMM | it->operand1);
-                               break;
-                       case BIND_OPCODE_SET_ADDEND_SLEB:
-                               if ( log ) fprintf(stderr, "BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", it->operand1);
-                               fEncodedData.append_byte(BIND_OPCODE_SET_ADDEND_SLEB);
-                               fEncodedData.append_sleb128(it->operand1);
-                               break;
-                       case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
-                               if ( log ) fprintf(stderr, "BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%lld, 0x%llX)\n", it->operand1, it->operand2);
-                               fEncodedData.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | it->operand1);
-                               fEncodedData.append_uleb128(it->operand2);
-                               break;
-                       case BIND_OPCODE_ADD_ADDR_ULEB:
-                               if ( log ) fprintf(stderr, "BIND_OPCODE_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
-                               fEncodedData.append_byte(BIND_OPCODE_ADD_ADDR_ULEB);
-                               fEncodedData.append_uleb128(it->operand1);
-                               break;
-                       case BIND_OPCODE_DO_BIND:
-                               if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND()\n");
-                               fEncodedData.append_byte(BIND_OPCODE_DO_BIND);
-                               break;
-                       case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
-                               if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
-                               fEncodedData.append_byte(BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB);
-                               fEncodedData.append_uleb128(it->operand1);
-                               break;
-                       case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
-                               if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(%lld=0x%llX)\n", it->operand1, it->operand1*sizeof(pint_t));
-                               fEncodedData.append_byte(BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED | it->operand1 );
-                               break;
-                       case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
-                               if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%lld, %lld)\n", it->operand1, it->operand2);
-                               fEncodedData.append_byte(BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB);
-                               fEncodedData.append_uleb128(it->operand1);
-                               fEncodedData.append_uleb128(it->operand2);
-                               break;
-               }
-       }
-       
-       // align to pointer size
-       fEncodedData.pad_to_size(sizeof(pint_t));
-
-       if (log) fprintf(stderr, "total binding info size = %ld\n", fEncodedData.size());
-
-}
-
-
-
-struct WeakBindingSorter
-{      
-     bool operator()(const BindingInfo& left, const BindingInfo& right)
-     {
-               // sort by symbol, type, address
-               if ( left.fSymbolName != right.fSymbolName )
-                       return ( strcmp(left.fSymbolName, right.fSymbolName) < 0 );
-               if ( left.fType != right.fType )
-                       return  (left.fType < right.fType);
-               return  (left.fAddress < right.fAddress);
-     }
-};
-
-
-
-template <typename A>
-void CompressedWeakBindingInfoLinkEditAtom<A>::encode()
-{
-       // add regular atoms that override a dylib's weak definitions 
-       for(std::set<const class ObjectFile::Atom*>::iterator it = fWriter.fRegularDefAtomsThatOverrideADylibsWeakDef->begin();
-                                                                                                       it != fWriter.fRegularDefAtomsThatOverrideADylibsWeakDef->end(); ++it) {
-               if ( fWriter.shouldExport(**it) )
-                       fWriter.fWeakBindingInfo.push_back(BindingInfo(0, (*it)->getName(), true, 0, 0));
-       }
-       
-       // add all exported weak definitions
-       for(std::vector<class ObjectFile::Atom*>::iterator it = fWriter.fAllAtoms->begin(); it != fWriter.fAllAtoms->end(); ++it) {
-               ObjectFile::Atom* atom = *it;
-               if ( (atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition) && fWriter.shouldExport(*atom) ) {
-                       fWriter.fWeakBindingInfo.push_back(BindingInfo(0, atom->getName(), false, 0, 0));
-               }
-       }       
-       
-       // sort by symbol, type, address
-       const std::vector<SegmentInfo*>& segments = fWriter.fSegmentInfos;
-       std::vector<BindingInfo>& info = fWriter.fWeakBindingInfo;
-       if ( info.size() == 0 )
-               return;
-       std::sort(info.begin(), info.end(), WeakBindingSorter());
-       
-       // convert to temp encoding that can be more easily optimized
-       std::vector<binding_tmp> mid;
-       mid.reserve(info.size());
-       const SegmentInfo* currentSegment = NULL;
-       unsigned int segIndex = 0;
-       const char* symbolName = NULL;
-       uint8_t type = 0;
-       uint64_t address = (uint64_t)(-1);
-       int64_t addend = 0;
-       for (std::vector<BindingInfo>::iterator it = info.begin(); it != info.end(); ++it) {
-               if ( symbolName != it->fSymbolName ) {
-                       mid.push_back(binding_tmp(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM, it->fFlags, 0, it->fSymbolName));
-                       symbolName = it->fSymbolName;
-               }
-               if ( it->fType != 0 ) {
-                       if ( type != it->fType ) {
-                               mid.push_back(binding_tmp(BIND_OPCODE_SET_TYPE_IMM, it->fType));
-                               type = it->fType;
-                       }
-                       if ( address != it->fAddress ) {
-                               // non weak symbols just have BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
-                               // weak symbols have SET_SEG, ADD_ADDR, SET_ADDED, DO_BIND
-                               if ( (currentSegment == NULL) || (it->fAddress < currentSegment->fBaseAddress) 
-                                               || ((currentSegment->fBaseAddress+currentSegment->fSize) <=it->fAddress) ) {
-                                       segIndex = 0;
-                                       for (std::vector<SegmentInfo*>::const_iterator segit = segments.begin(); segit != segments.end(); ++segit) {
-                                               if ( ((*segit)->fBaseAddress <= it->fAddress) && (it->fAddress < ((*segit)->fBaseAddress+(*segit)->fSize)) ) {
-                                                       currentSegment = *segit;
-                                                       break;
-                                               }
-                                               ++segIndex;
-                                       }
-                                       mid.push_back(binding_tmp(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, segIndex, it->fAddress - currentSegment->fBaseAddress));
-                               }
-                               else {
-                                       mid.push_back(binding_tmp(BIND_OPCODE_ADD_ADDR_ULEB, it->fAddress-address));
-                               }
-                               address = it->fAddress;
-                       }
-                       if ( addend != it->fAddend ) {
-                               mid.push_back(binding_tmp(BIND_OPCODE_SET_ADDEND_SLEB, it->fAddend));
-                               addend = it->fAddend;
-                       }
-                       mid.push_back(binding_tmp(BIND_OPCODE_DO_BIND, 0));
-                       address += sizeof(pint_t);
-               }
-       }
-       mid.push_back(binding_tmp(BIND_OPCODE_DONE, 0));
-
-
-       // optimize phase 1, combine bind/add pairs
-       binding_tmp* dst = &mid[0];
-       for (const binding_tmp* src = &mid[0]; src->opcode != BIND_OPCODE_DONE; ++src) {
-               if ( (src->opcode == BIND_OPCODE_DO_BIND) 
-                               && (src[1].opcode == BIND_OPCODE_ADD_ADDR_ULEB) ) {
-                       dst->opcode = BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB;
-                       dst->operand1 = src[1].operand1;
-                       ++src;
-                       ++dst;
-               }
-               else {
-                       *dst++ = *src;
-               }
-       }
-       dst->opcode = BIND_OPCODE_DONE;
-
-       // optimize phase 2, compress packed runs of BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB with
-       // same addr delta into one BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
-       dst = &mid[0];
-       for (const binding_tmp* src = &mid[0]; src->opcode != BIND_OPCODE_DONE; ++src) {
-               uint64_t delta = src->operand1;
-               if ( (src->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB) 
-                               && (src[1].opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB) 
-                               && (src[1].operand1 == delta) ) {
-                       // found at least two in a row, this is worth compressing
-                       dst->opcode = BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB;
-                       dst->operand1 = 1;
-                       dst->operand2 = delta;
-                       ++src;
-                       while ( (src->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB)
-                                       && (src->operand1 == delta) ) {
-                               dst->operand1++;
-                               ++src;
-                       }
-                       --src;
-                       ++dst;
-               }
-               else {
-                       *dst++ = *src;
-               }
-       }
-       dst->opcode = BIND_OPCODE_DONE;
-       
-       // optimize phase 3, use immediate encodings
-       for (binding_tmp* p = &mid[0]; p->opcode != REBASE_OPCODE_DONE; ++p) {
-               if ( (p->opcode == BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB) 
-                       && (p->operand1 < (15*sizeof(pint_t)))
-                       && ((p->operand1 % sizeof(pint_t)) == 0) ) {
-                       p->opcode = BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED;
-                       p->operand1 = p->operand1/sizeof(pint_t);
-               }
-       }       
-       dst->opcode = BIND_OPCODE_DONE;
-
-
-       // convert to compressed encoding
-       const static bool log = false;
-       fEncodedData.reserve(info.size()*2);
-       bool done = false;
-       for (std::vector<binding_tmp>::iterator it = mid.begin(); !done && it != mid.end() ; ++it) {
-               switch ( it->opcode ) {
-                       case BIND_OPCODE_DONE:
-                               if ( log ) fprintf(stderr, "BIND_OPCODE_DONE()\n");
-                               fEncodedData.append_byte(BIND_OPCODE_DONE);
-                               done = true;
-                               break;
-                       case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
-                               if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%lld)\n", it->operand1);
-                               fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | it->operand1);
-                               break;
-                       case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
-                               if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%lld)\n", it->operand1);
-                               fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
-                               fEncodedData.append_uleb128(it->operand1);
-                               break;
-                       case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
-                               if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%lld)\n", it->operand1);
-                               fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | (it->operand1 & BIND_IMMEDIATE_MASK));
-                               break;
-                       case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
-                               if ( log ) fprintf(stderr, "BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%0llX, %s)\n", it->operand1, it->name);
-                               fEncodedData.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | it->operand1);
-                               fEncodedData.append_string(it->name);
-                               break;
-                       case BIND_OPCODE_SET_TYPE_IMM:
-                               if ( log ) fprintf(stderr, "BIND_OPCODE_SET_TYPE_IMM(%lld)\n", it->operand1);
-                               fEncodedData.append_byte(BIND_OPCODE_SET_TYPE_IMM | it->operand1);
-                               break;
-                       case BIND_OPCODE_SET_ADDEND_SLEB:
-                               if ( log ) fprintf(stderr, "BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", it->operand1);
-                               fEncodedData.append_byte(BIND_OPCODE_SET_ADDEND_SLEB);
-                               fEncodedData.append_sleb128(it->operand1);
-                               break;
-                       case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
-                               if ( log ) fprintf(stderr, "BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%lld, 0x%llX)\n", it->operand1, it->operand2);
-                               fEncodedData.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | it->operand1);
-                               fEncodedData.append_uleb128(it->operand2);
-                               break;
-                       case BIND_OPCODE_ADD_ADDR_ULEB:
-                               if ( log ) fprintf(stderr, "BIND_OPCODE_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
-                               fEncodedData.append_byte(BIND_OPCODE_ADD_ADDR_ULEB);
-                               fEncodedData.append_uleb128(it->operand1);
-                               break;
-                       case BIND_OPCODE_DO_BIND:
-                               if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND()\n");
-                               fEncodedData.append_byte(BIND_OPCODE_DO_BIND);
-                               break;
-                       case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
-                               if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
-                               fEncodedData.append_byte(BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB);
-                               fEncodedData.append_uleb128(it->operand1);
-                               break;
-                       case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
-                               if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(%lld=0x%llX)\n", it->operand1, it->operand1*sizeof(pint_t));
-                               fEncodedData.append_byte(BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED | it->operand1 );
-                               break;
-                       case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
-                               if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%lld, %lld)\n", it->operand1, it->operand2);
-                               fEncodedData.append_byte(BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB);
-                               fEncodedData.append_uleb128(it->operand1);
-                               fEncodedData.append_uleb128(it->operand2);
-                               break;
-               }
-       }
-       
-       // align to pointer size
-       fEncodedData.pad_to_size(sizeof(pint_t));
-
-       if (log) fprintf(stderr, "total weak binding info size = %ld\n", fEncodedData.size());
-
-}
-
-template <typename A>
-void CompressedLazyBindingInfoLinkEditAtom<A>::encode()
-{
-       // stream all lazy bindings and record start offsets
-       const SegmentInfo* currentSegment = NULL;
-       uint8_t segIndex = 0;
-       const std::vector<SegmentInfo*>& segments = fWriter.fSegmentInfos;
-       std::vector<class LazyPointerAtom<A>*>& allLazys = fWriter.fAllSynthesizedLazyPointers;
-       for (typename std::vector<class LazyPointerAtom<A>*>::iterator it = allLazys.begin(); it != allLazys.end(); ++it) {
-               LazyPointerAtom<A>* lazyPointerAtom = *it;
-               ObjectFile::Atom* lazyPointerTargetAtom = lazyPointerAtom->getTarget();
-               
-               // skip lazy pointers that are bound non-lazily because they are coalesced
-               if ( ! fWriter.targetRequiresWeakBinding(*lazyPointerTargetAtom) ) {                    
-                       // record start offset for use by stub helper
-                       lazyPointerAtom->setLazyBindingInfoOffset(fEncodedData.size());
-
-                       // write address to bind
-                       pint_t address = lazyPointerAtom->getAddress();
-                       if ( (currentSegment == NULL) || (address < currentSegment->fBaseAddress) 
-                                       || ((currentSegment->fBaseAddress+currentSegment->fSize) <= address) ) {
-                               segIndex = 0;
-                               for (std::vector<SegmentInfo*>::const_iterator segit = segments.begin(); segit != segments.end(); ++segit) {
-                                       if ( ((*segit)->fBaseAddress <= address) && (address < ((*segit)->fBaseAddress+(*segit)->fSize)) ) {
-                                               currentSegment = *segit;
-                                               break;
-                                       }
-                                       ++segIndex;
-                               }
-                       }
-                       fEncodedData.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segIndex);
-                       fEncodedData.append_uleb128(lazyPointerAtom->getAddress() - currentSegment->fBaseAddress);
-                       
-                       // write ordinal
-                       int ordinal = fWriter.compressedOrdinalForImortedAtom(lazyPointerTargetAtom);
-                       if ( ordinal <= 0 ) {
-                               // special lookups are encoded as negative numbers in BindingInfo
-                               fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | (ordinal & BIND_IMMEDIATE_MASK) );
-                       }
-                       else if ( ordinal <= 15 ) {
-                               // small ordinals are encoded in opcode
-                               fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | ordinal);
-                       }
-                       else {
-                               fEncodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
-                               fEncodedData.append_uleb128(ordinal);
-                       }
-                       // write symbol name
-                       bool weak_import = fWriter.fWeakImportMap[lazyPointerTargetAtom];
-                       if ( weak_import )
-                               fEncodedData.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | BIND_SYMBOL_FLAGS_WEAK_IMPORT);
-                       else
-                               fEncodedData.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM);
-                       fEncodedData.append_string(lazyPointerTargetAtom->getName());
-                       // write do bind
-                       fEncodedData.append_byte(BIND_OPCODE_DO_BIND);
-                       fEncodedData.append_byte(BIND_OPCODE_DONE);
-               }
-       }
-       // align to pointer size
-       fEncodedData.pad_to_size(sizeof(pint_t));
-       
-       //fprintf(stderr, "lazy binding info size = %ld, for %ld entries\n", fEncodedData.size(), allLazys.size());
-}
-       
-struct TrieEntriesSorter
-{
-       TrieEntriesSorter(Options& o) : fOptions(o) {}
-       
-     bool operator()(const mach_o::trie::Entry& left, const mach_o::trie::Entry& right)
-     {
-               unsigned int leftOrder;
-               unsigned int rightOrder;
-               fOptions.exportedSymbolOrder(left.name, &leftOrder);
-               fOptions.exportedSymbolOrder(right.name, &rightOrder);
-               if ( leftOrder != rightOrder ) 
-                       return (leftOrder < rightOrder);
-               else
-                       return (left.address < right.address);
-     }
-private:
-       Options&        fOptions;
-};
-
-
-template <typename A>
-void CompressedExportInfoLinkEditAtom<A>::encode()
-{
-       // make vector of mach_o::trie::Entry for all exported symbols
-       std::vector<class ObjectFile::Atom*>& exports = fWriter.fExportedAtoms;
-       uint64_t imageBaseAddress = fWriter.fMachHeaderAtom->getAddress();
-       std::vector<mach_o::trie::Entry> entries;
-       entries.reserve(exports.size());
-       for (std::vector<ObjectFile::Atom*>::iterator it = exports.begin(); it != exports.end(); ++it) {
-               ObjectFile::Atom* atom = *it;
-               uint64_t flags = 0;
-               if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition )
-                       flags |= EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION;
-               uint64_t address = atom->getAddress() - imageBaseAddress;
-               if ( atom->isThumb() )
-                       address |= 1;
-               mach_o::trie::Entry entry;
-               entry.name = atom->getName();
-               entry.flags = flags;
-               entry.address = address; 
-               entries.push_back(entry);
-       }
-
-       // sort vector by -exported_symbols_order, and any others by address
-       std::sort(entries.begin(), entries.end(), TrieEntriesSorter(fWriter.fOptions));
-       
-       // create trie
-       mach_o::trie::makeTrie(entries, fEncodedData.bytes());
-
-       // align to pointer size
-       fEncodedData.pad_to_size(sizeof(pint_t));
-}
-
-
-
-
-
-}; // namespace executable
-}; // namespace mach_o
-
-
-#endif // __EXECUTABLE_MACH_O__
diff --git a/src/ld/ObjectFile.h b/src/ld/ObjectFile.h
deleted file mode 100644 (file)
index 2710bfb..0000000
+++ /dev/null
@@ -1,385 +0,0 @@
-/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
- *
- * Copyright (c) 2005-2007 Apple Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-
-#ifndef __OBJECTFILE__
-#define __OBJECTFILE__
-
-#include <stdint.h>
-#include <vector>
-#include <map>
-#include <set>
-
-
-
-//
-// These classes represent the abstract Atoms and References that are the basis of the linker.
-// An Atom and a Reference correspond to a Node and Edge in graph theory.
-//
-// A Reader is a class which parses an object file and presents it as Atoms and References.
-// All linking operations are done on Atoms and References.  This makes the linker file
-// format independent.
-//
-// A Writer takes a vector of Atoms with all References resolved and produces an executable file.
-//
-//
-
-
-
-namespace ObjectFile {
-
-
-struct LineInfo
-{
-       uint32_t        atomOffset;
-       const char* fileName;
-       uint32_t        lineNumber;
-};
-
-
-class ReaderOptions
-{
-public:
-                                               ReaderOptions() : fFullyLoadArchives(false), fLoadAllObjcObjectsFromArchives(false), fFlatNamespace(false),
-                                                                               fLinkingMainExecutable(false), 
-                                                                               fForFinalLinkedImage(false), fNoEHLabels(false), fForStatic(false), fForDyld(false), fMakeTentativeDefinitionsReal(false), 
-                                                                               fWhyLoad(false), fRootSafe(false), fSetuidSafe(false),fDebugInfoStripping(kDebugInfoFull),
-                                                                               fImplicitlyLinkPublicDylibs(true),
-                                                                               fAddCompactUnwindEncoding(true), 
-                                                                               fWarnCompactUnwind(false),
-                                                                               fRemoveDwarfUnwindIfCompactExists(false),
-                                                                               fMakeCompressedDyldInfo(false),
-                                                                               fAutoOrderInitializers(true),
-                                                                               fOptimizeZeroFill(true),
-                                                                               fLogObjectFiles(false), fLogAllFiles(false),
-                                                                               fTraceDylibs(false), fTraceIndirectDylibs(false), fTraceArchives(false), 
-                                                                               fTraceOutputFile(NULL), fMacVersionMin(kMinMacVersionUnset), fIPhoneVersionMin(kMinIPhoneVersionUnset) {}
-       enum DebugInfoStripping { kDebugInfoNone, kDebugInfoMinimal, kDebugInfoFull };
-       enum MacVersionMin { kMinMacVersionUnset, k10_1, k10_2, k10_3, k10_4, k10_5, k10_6, k10_7 };
-       enum IPhoneVersionMin { kMinIPhoneVersionUnset, k2_0, k2_1, k2_2, k3_0, k3_1, k3_2, k4_0 };
-
-       struct AliasPair {
-               const char*                     realName;
-               const char*                     alias;
-       };
-
-       bool                                    fFullyLoadArchives;
-       bool                                    fLoadAllObjcObjectsFromArchives;
-       bool                                    fFlatNamespace;
-       bool                                    fLinkingMainExecutable;
-       bool                                    fForFinalLinkedImage;
-       bool                                    fNoEHLabels;
-       bool                                    fForStatic;
-       bool                                    fForDyld;
-       bool                                    fMakeTentativeDefinitionsReal;
-       bool                                    fWhyLoad;
-       bool                                    fRootSafe;
-       bool                                    fSetuidSafe;
-       DebugInfoStripping              fDebugInfoStripping;
-       bool                                    fImplicitlyLinkPublicDylibs;
-       bool                                    fAddCompactUnwindEncoding;
-       bool                                    fWarnCompactUnwind;
-       bool                                    fRemoveDwarfUnwindIfCompactExists;
-       bool                                    fMakeCompressedDyldInfo;
-       bool                                    fAutoOrderInitializers;
-       bool                                    fOptimizeZeroFill;
-       bool                                    fLogObjectFiles;
-       bool                                    fLogAllFiles;
-       bool                                    fTraceDylibs;
-       bool                                    fTraceIndirectDylibs;
-       bool                                    fTraceArchives;
-       const char*                             fTraceOutputFile;
-       MacVersionMin                   fMacVersionMin;
-       IPhoneVersionMin                fIPhoneVersionMin;
-       std::vector<AliasPair>  fAliases;
-};
-
-
-class Reader
-{
-public:
-       enum DebugInfoKind { kDebugInfoNone=0, kDebugInfoStabs=1, kDebugInfoDwarf=2, kDebugInfoStabsUUID=3 };
-       struct Stab
-       {
-               class Atom*     atom;
-               uint8_t         type;
-               uint8_t         other;
-               uint16_t        desc;
-               uint32_t        value;
-               const char* string;
-       };
-       enum ObjcConstraint { kObjcNone,  kObjcRetainRelease,  kObjcRetainReleaseOrGC,  kObjcGC };
-       enum CpuConstraint  { kCpuAny = 0 };
-
-       class DylibHander
-       {
-       public:
-               virtual                         ~DylibHander()  {}
-               virtual Reader*         findDylib(const char* installPath, const char* fromPath) = 0;
-       };
-
-
-       static Reader* createReader(const char* path, const ReaderOptions& options);
-
-       virtual const char*                                     getPath() = 0;
-       virtual time_t                                          getModificationTime() = 0;
-       virtual DebugInfoKind                           getDebugInfoKind() = 0;
-       virtual std::vector<class Atom*>&       getAtoms() = 0;
-       virtual std::vector<class Atom*>*       getJustInTimeAtomsFor(const char* name) = 0;
-       virtual std::vector<Stab>*                      getStabs() = 0;
-       virtual ObjcConstraint                          getObjCConstraint()                     { return kObjcNone; }
-       virtual uint32_t                                        updateCpuConstraint(uint32_t current) { return current; }
-       virtual bool                                            objcReplacementClasses()        { return false; }
-
-       // For relocatable object files only
-       virtual bool                                            canScatterAtoms()                       { return true; }
-       virtual bool                                            optimize(const std::vector<ObjectFile::Atom*>&, std::vector<ObjectFile::Atom*>&, 
-                                                                                                       std::vector<const char*>&, const std::set<ObjectFile::Atom*>&,
-                                                                                                       std::vector<ObjectFile::Atom*>&,
-                                                                                                       uint32_t, ObjectFile::Reader* writer, 
-                                                                                                       ObjectFile::Atom* entryPointAtom,
-                                                                                                       const std::vector<const char*>& llvmOptions,
-                                                                                                       bool allGlobalsAReDeadStripRoots, int okind, 
-                                                                                                       bool verbose, bool saveTemps, const char* outputFilePath,
-                                                                                                       bool pie, bool allowTextRelocs) { return false; }
-       virtual bool                                            hasLongBranchStubs()            { return false; }
-
-       // For Dynamic Libraries only
-       virtual const char*                                     getInstallPath()                        { return NULL; }
-       virtual uint32_t                                        getTimestamp()                          { return 0; }
-       virtual uint32_t                                        getCurrentVersion()                     { return 0; }
-       virtual uint32_t                                        getCompatibilityVersion()       { return 0; }
-       virtual void                                            processIndirectLibraries(DylibHander* handler)  { }
-       virtual void                                            setExplicitlyLinked()           { }
-       virtual bool                                            explicitlyLinked()                      { return false; }
-       virtual bool                                            implicitlyLinked()                      { return false; }
-       virtual bool                                            providedExportAtom()            { return false; }
-       virtual const char*                                     parentUmbrella()                        { return NULL; }
-       virtual std::vector<const char*>*       getAllowableClients()           { return NULL; }
-       virtual bool                                            hasWeakExternals()                      { return false; }
-       virtual bool                                            deadStrippable()                        { return false; }
-       virtual bool                                            isLazyLoadedDylib()                     { return false; }
-
-protected:
-                                                                               Reader() {}
-       virtual                                                         ~Reader() {}
-};
-
-class Segment
-{
-public:
-       virtual const char*                     getName() const  = 0;
-       virtual bool                            isContentReadable() const = 0;
-       virtual bool                            isContentWritable() const = 0;
-       virtual bool                            isContentExecutable() const = 0;
-
-       uint64_t                                        getBaseAddress() const { return fBaseAddress; }
-       void                                            setBaseAddress(uint64_t addr) { fBaseAddress = addr; }
-       virtual bool                            hasFixedAddress() const { return false; }
-
-protected:
-                                                               Segment() : fBaseAddress(0) {}
-       virtual                                         ~Segment() {}
-       uint64_t                                        fBaseAddress;
-};
-
-class Reference;
-
-class Section
-{
-public:
-       unsigned int    getIndex() { return fIndex; }
-       uint64_t                getBaseAddress() { return fBaseAddress; }
-       void                    setBaseAddress(uint64_t addr) { fBaseAddress = addr; }
-       void*                   fOther;
-
-protected:
-                                       Section() : fOther(NULL), fBaseAddress(0), fIndex(0)  {}
-       uint64_t                fBaseAddress;
-       unsigned int    fIndex;
-};
-
-
-struct Alignment 
-{ 
-                               Alignment(int p2, int m=0) : powerOf2(p2), modulus(m) {}
-       uint8_t         trailingZeros() const { return (modulus==0) ? powerOf2 : __builtin_ctz(modulus); }
-       uint16_t        powerOf2;  
-       uint16_t        modulus; 
-};
-
-struct UnwindInfo
-{
-       uint32_t        startOffset;
-       uint32_t        unwindInfo;
-       
-       typedef UnwindInfo* iterator;
-
-};
-
-//
-// An atom is the fundamental unit of linking.  A C function or global variable is an atom.
-// An atom has content and some attributes. The content of a function atom is the instructions
-// that implement the function.  The content of a global variable atom is its initial bits.
-//
-// Name:
-// The name of an atom is the label name generated by the compiler.  A C compiler names foo()
-// as _foo.  A C++ compiler names foo() as __Z3foov.
-// The name refers to the first byte of the content.  An atom cannot have multiple entry points.
-// Such code is modeled as multiple atoms, each having a "follow on" reference to the next.
-// A "follow on" reference is a contraint to the linker to the atoms must be laid out contiguously.
-//
-// Scope:
-// An atom is in one of three scopes: translation-unit, linkage-unit, or global.  These correspond
-// to the C visibility of static, hidden, default.
-//
-// DefinitionKind:
-// An atom is one of five defintion kinds:
-//     regular                 Most atoms.
-//     weak                    C++ compiler makes some functions weak if there might be multiple copies
-//                                     that the linker needs to coalesce.
-//     tentative               A straggler from ancient C when the extern did not exist. "int foo;" is ambiguous.
-//                                     It could be a prototype or it could be a definition.
-//     external                This is a "proxy" atom produced by a dylib reader.  It has no content.  It exists
-//                                     so that all References can be resolved.
-//     external-weak   Same as external, but the definition in the dylib is weak.
-//
-// SymbolTableInclusion:
-// An atom may or may not be in the symbol table in an object file.
-//  in                         Most atoms for functions or global data
-//     not-in                  Anonymous atoms such literal c-strings, or other compiler generated data
-//     in-never-strip  Atom whose name the strip tool should never remove (e.g. REFERENCED_DYNAMICALLY in mach-o)
-//
-// Ordinal:
-// When a reader is created it is given a base ordinal number.  All atoms created by the reader
-// should return a contiguous range of ordinal values that start at the base ordinal.  The ordinal
-// values are used by the linker to sort the atom graph when producing the output file. 
-//
-class Atom
-{
-public:
-       enum Scope { scopeTranslationUnit, scopeLinkageUnit, scopeGlobal };
-       enum DefinitionKind { kRegularDefinition, kWeakDefinition, kTentativeDefinition, kExternalDefinition, kExternalWeakDefinition, kAbsoluteSymbol };
-       enum ContentType { kUnclassifiedType, kCStringType, kCFIType, kLSDAType, kSectionStart, kSectionEnd, kBranchIsland, 
-                                       kLazyPointer, kStub, kNonLazyPointer, kLazyDylibPointer, kStubHelper };
-       enum SymbolTableInclusion { kSymbolTableNotIn, kSymbolTableIn, kSymbolTableInAndNeverStrip, kSymbolTableInAsAbsolute };
-
-       virtual Reader*                                                 getFile() const = 0;
-       virtual bool                                                    getTranslationUnitSource(const char** dir, const char** name) const = 0;
-       virtual const char*                                             getName() const = 0;
-       virtual const char*                                             getDisplayName() const = 0;
-       virtual Scope                                                   getScope() const = 0;
-       virtual DefinitionKind                                  getDefinitionKind() const = 0;
-       virtual ContentType                                             getContentType() const { return kUnclassifiedType; }
-       virtual SymbolTableInclusion                    getSymbolTableInclusion() const = 0;
-       virtual bool                                                    dontDeadStrip() const = 0;
-       virtual bool                                                    isZeroFill() const = 0;
-       virtual bool                                                    isThumb() const = 0;
-       virtual uint64_t                                                getSize() const = 0;
-       virtual std::vector<ObjectFile::Reference*>&  getReferences() const = 0;
-       virtual bool                                                    mustRemainInSection() const = 0;
-       virtual const char*                                             getSectionName() const = 0;
-       virtual Segment&                                                getSegment() const = 0;
-       virtual Atom&                                                   getFollowOnAtom() const = 0;
-       virtual uint32_t                                                getOrdinal() const = 0;
-       virtual std::vector<LineInfo>*                  getLineInfo() const = 0;
-       virtual Alignment                                               getAlignment() const = 0;
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const = 0;
-       virtual void                                                    setScope(Scope) = 0;
-       virtual UnwindInfo::iterator                    beginUnwind() { return NULL; }
-       virtual UnwindInfo::iterator                    endUnwind() { return NULL; }
-       virtual Reference*                                              getLSDA() { return NULL; }
-       virtual Reference*                                              getFDE() { return NULL; }
-       virtual Atom*                                                   getPersonalityPointer() { return NULL; }
-
-                       uint64_t                                                getSectionOffset() const        { return fSectionOffset; }
-                       uint64_t                                                getAddress() const      { return fSection->getBaseAddress() + fSectionOffset; }
-                       class Section*                                  getSection() const { return fSection; }
-
-       virtual void                                                    setSectionOffset(uint64_t offset) { fSectionOffset = offset; }
-       virtual void                                                    setSection(class Section* sect) { fSection = sect; }
-
-protected:
-                                                                                       Atom() :  fSectionOffset(0), fSection(NULL) {}
-               virtual                                                         ~Atom() {}
-
-               uint64_t                                                        fSectionOffset;
-               class Section*                                          fSection;
-};
-
-
-//
-// A Reference is a directed edge to another Atom.  When an instruction in
-// the content of an Atom refers to another Atom, that is represented by a
-// Reference.
-//
-// There are two kinds of references: direct and by-name.  With a direct Reference,
-// the target is bound by the Reader that created it.  For instance a reference to a
-// static would produce a direct reference.  A by-name reference requires the linker
-// to find the target Atom with the required name in order to be bound.
-//
-// For a link to succeed all References must be bound.
-//
-// A Reference has an optional "from" target.  This is used when the content to fix-up
-// is the difference of two Atom address.  For instance, if a pointer sized data Atom
-// is to contain A - B, then the Atom would have on Reference with a target of "A" and
-// a from-target of "B".
-//
-// A Reference also has a fix-up-offset.  This is the offset into the content of the
-// Atom holding the reference where the fix-up (relocation) will be applied.
-//
-//
-//
-class Reference
-{
-public:
-       enum TargetBinding { kUnboundByName, kBoundDirectly, kBoundByName, kDontBind };
-
-       virtual TargetBinding   getTargetBinding() const = 0;
-       virtual TargetBinding   getFromTargetBinding() const = 0;
-       virtual uint8_t                 getKind() const = 0;
-       virtual uint64_t                getFixUpOffset() const = 0;
-       virtual const char*             getTargetName() const = 0;
-       virtual Atom&                   getTarget() const = 0;
-       virtual uint64_t                getTargetOffset() const = 0;
-       virtual Atom&                   getFromTarget() const = 0;
-       virtual const char*             getFromTargetName() const = 0;
-       virtual uint64_t                getFromTargetOffset() const = 0;
-
-       virtual void                    setTarget(Atom&, uint64_t offset) = 0;
-       virtual void                    setFromTarget(Atom&) = 0;
-       virtual const char*             getDescription() const = 0;
-       virtual bool                    isBranch() const  { return false; }
-
-protected:
-                                                       Reference() {}
-       virtual                                 ~Reference() {}
-};
-
-
-};     // namespace ObjectFile
-
-
-#endif // __OBJECTFILE__
diff --git a/src/ld/OpaqueSection.hpp b/src/ld/OpaqueSection.hpp
deleted file mode 100644 (file)
index cddd45c..0000000
+++ /dev/null
@@ -1,199 +0,0 @@
-/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
- *
- * Copyright (c) 2005-2006 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
- */
-
-#ifndef __OPAQUE_SECTION__
-#define __OPAQUE_SECTION__
-
-
-#include <vector>
-
-#include "ObjectFile.h"
-
-namespace opaque_section {
-
-
-class Segment : public ObjectFile::Segment
-{
-public:
-                                                               Segment(const char* name)               { fName = name; }
-       virtual const char*                     getName() const                                 { return fName; }
-       virtual bool                            isContentReadable() const               { return true; }
-       virtual bool                            isContentWritable() const               { return false; }
-       virtual bool                            isContentExecutable() const             { return (strcmp(fName, "__TEXT") == 0); }
-private:
-       const char*                                     fName;
-};
-
-
-class Reader : public ObjectFile::Reader 
-{
-public:
-                                                                                               Reader(const char* segmentName, const char* sectionName, const char* path, 
-                                                                                                       const uint8_t fileContent[], uint64_t fileLength, uint32_t ordinal, const char* symbolName=NULL);
-       virtual                                                                         ~Reader();
-       
-       void                                                                                    addSectionReference(uint8_t kind, uint64_t offsetInSection, const ObjectFile::Atom* targetAtom, 
-                                                                                                                                               uint64_t offsetInTarget, const ObjectFile::Atom* fromTargetAtom=NULL, uint64_t offsetInFromTarget=0);
-       
-       virtual const char*                                                             getPath()                                                               { return fPath; }
-       virtual time_t                                                                  getModificationTime()                                   { return 0; }
-       virtual DebugInfoKind                                                   getDebugInfoKind()                                              { return ObjectFile::Reader::kDebugInfoNone; }
-       virtual std::vector<class ObjectFile::Atom*>&   getAtoms()                                                              { return fAtoms; }
-       virtual std::vector<class ObjectFile::Atom*>*   getJustInTimeAtomsFor(const char* name) { return NULL; }
-       virtual std::vector<Stab>*                                              getStabs()                                                              { return NULL; }
-
-private:
-       const char*                                                                             fPath;
-       std::vector<class ObjectFile::Atom*>                    fAtoms;
-};
-
-class Reference : public ObjectFile::Reference
-{
-public:
-                                                       Reference(uint8_t kind, uint64_t fixupOffset, const ObjectFile::Atom* target, uint64_t targetOffset,
-                                                                               const ObjectFile::Atom* fromTarget=NULL, uint64_t fromTargetOffset=0)
-                                                               : fFixUpOffset(fixupOffset), fTarget(target), fTargetOffset(targetOffset), fKind(kind), 
-                                                                       fFromTarget(fromTarget), fFromTargetOffset(fromTargetOffset)  {}
-       virtual                                 ~Reference() {}
-
-
-       virtual ObjectFile::Reference::TargetBinding    getTargetBinding() const        { return ObjectFile::Reference::kBoundDirectly; }
-       virtual ObjectFile::Reference::TargetBinding    getFromTargetBinding() const{ return ObjectFile::Reference::kDontBind; }
-       virtual uint8_t                                                                 getKind() const                         { return fKind; }
-       virtual uint64_t                                                                getFixUpOffset() const          { return fFixUpOffset; }
-       virtual const char*                                                             getTargetName() const           { return fTarget->getName(); }
-       virtual ObjectFile::Atom&                                               getTarget() const                       { return *((ObjectFile::Atom*)fTarget); }
-       virtual uint64_t                                                                getTargetOffset() const         { return fTargetOffset; }
-       virtual ObjectFile::Atom&                                               getFromTarget() const           { return *((ObjectFile::Atom*)fFromTarget); }
-       virtual const char*                                                             getFromTargetName() const       { return fFromTarget->getName();  }
-       virtual uint64_t                                                                getFromTargetOffset() const { return fFromTargetOffset; }
-       virtual void                                                                    setTarget(ObjectFile::Atom&, uint64_t offset) { throw "can't set target"; }
-       virtual void                                                                    setFromTarget(ObjectFile::Atom&) { throw "can't set from target"; }
-       virtual const char*                                                             getDescription() const          { return "opaque section reference"; }
-
-private:
-       uint64_t                                fFixUpOffset;
-       const ObjectFile::Atom* fTarget;
-       uint64_t                                fTargetOffset;
-       uint8_t                                 fKind;
-       const ObjectFile::Atom* fFromTarget;
-       uint64_t                                fFromTargetOffset;
-};
-
-
-class Atom : public ObjectFile::Atom {
-public:
-       virtual ObjectFile::Reader*                                     getFile() const                         { return &fOwner; }
-       virtual bool                                                            getTranslationUnitSource(const char** dir, const char** name) const { return false; }
-       virtual const char*                                                     getName() const                         { return fName; }
-       virtual const char*                                                     getDisplayName() const;
-       virtual Scope                                                           getScope() const                        { return ObjectFile::Atom::scopeLinkageUnit; }
-       virtual DefinitionKind                                          getDefinitionKind() const       { return kRegularDefinition; }
-       virtual SymbolTableInclusion                            getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
-       virtual bool                                                            dontDeadStrip() const           { return true; }
-       virtual bool                                                            isZeroFill() const                      { return false; }
-       virtual bool                                                            isThumb() const                         { return false; }
-       virtual uint64_t                                                        getSize() const                         { return fFileLength; }
-       virtual std::vector<ObjectFile::Reference*>&  getReferences() const             { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
-       virtual bool                                                            mustRemainInSection() const { return false; }
-       virtual const char*                                                     getSectionName() const          { return fSectionName; }
-       virtual Segment&                                                        getSegment() const                      { return fSegment; }
-       virtual ObjectFile::Atom&                                       getFollowOnAtom() const         { return *((ObjectFile::Atom*)NULL); }
-       virtual uint32_t                                                        getOrdinal() const                      { return fOrdinal; }
-       virtual std::vector<ObjectFile::LineInfo>*      getLineInfo() const                     { return NULL; }
-       virtual ObjectFile::Alignment                           getAlignment() const            { return ObjectFile::Alignment(4); }
-       virtual void                                                            copyRawContent(uint8_t buffer[]) const;
-
-       virtual void                                                            setScope(Scope)                         { }
-
-protected:
-       friend class Reader;
-       
-                                                                                       Atom(Reader& owner, Segment& segment, const char* sectionName, 
-                                                                                               const uint8_t fileContent[], uint64_t fileLength, uint32_t ordinal, const char* symbolName);
-       virtual                                                                 ~Atom() {}
-       
-       Reader&                                                                 fOwner;
-       Segment&                                                                fSegment;
-       const char*                                                             fName;
-       const char*                                                             fSectionName;
-       const uint8_t*                                                  fFileContent;
-       uint32_t                                                                fOrdinal;
-       uint64_t                                                                fFileLength;
-       std::vector<ObjectFile::Reference*>             fReferences;
-};
-
-
-       
-Atom::Atom(Reader& owner, Segment& segment, const char* sectionName, const uint8_t fileContent[], uint64_t fileLength, uint32_t ordinal, const char* symbolName) 
-       : fOwner(owner), fSegment(segment), fSectionName(sectionName), fFileContent(fileContent), fOrdinal(ordinal), fFileLength(fileLength) 
-{ 
-       if ( symbolName != NULL )
-               fName = strdup(symbolName);
-       else
-               asprintf((char**)&fName, "__section$%s%s", segment.getName(), sectionName);
-}
-
-
-Reader::Reader(const char* segmentName, const char* sectionName, const char* path, const uint8_t fileContent[], 
-                       uint64_t fileLength, uint32_t ordinal, const char* symbolName)
- : fPath(path)
-{
-       fAtoms.push_back(new Atom(*this, *(new Segment(segmentName)), strdup(sectionName), fileContent, fileLength, ordinal, symbolName));
-}
-
-Reader::~Reader()
-{
-}
-
-void Reader::addSectionReference(uint8_t kind, uint64_t offsetInSection, const ObjectFile::Atom* targetAtom, 
-                                                               uint64_t offsetInTarget, const ObjectFile::Atom* fromTargetAtom, uint64_t offsetInFromTarget)
-{
-       fAtoms[0]->getReferences().push_back(new Reference(kind, offsetInSection, targetAtom, offsetInTarget, fromTargetAtom, offsetInFromTarget));
-}
-
-
-const char*     Atom::getDisplayName() const
-{
-       static char name[64];
-       sprintf(name, "opaque section %s %s", fSegment.getName(), fSectionName);
-       return name;
-}
-
-
-void Atom::copyRawContent(uint8_t buffer[]) const
-{
-       memcpy(buffer, fFileContent, fFileLength);
-}
-
-
-
-};
-
-
-
-#endif // __OPAQUE_SECTION__
-
-
-
index 492d140b4c780eb9b8d695589ad6347c6a12ac85..1de337988a27f6928efac0e1e086d01e25b3bf9f 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2005-2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2005-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -28,6 +28,7 @@
 #include <mach/vm_prot.h>
 #include <mach-o/dyld.h>
 #include <fcntl.h>
+
 #include <vector>
 
 #include "configure.h"
 #include "Architectures.hpp"
 #include "MachOFileAbstraction.hpp"
 
-extern void printLTOVersion(Options &opts);
+// upward dependency on lto::version()
+namespace lto {
+       extern const char* version();
+}
 
 // magic to place command line in crash reports
+const int crashreporterBufferSize = 2000;
 extern "C" char* __crashreporter_info__;
-static char crashreporterBuffer[1000];
+static char crashreporterBuffer[crashreporterBufferSize];
 char* __crashreporter_info__ = crashreporterBuffer;
 
 static bool                    sEmitWarnings = true;
@@ -81,31 +86,54 @@ void throwf(const char* format, ...)
 }
 
 Options::Options(int argc, const char* argv[])
-       : fOutputFile("a.out"), fArchitecture(0), fSubArchitecture(0), fOutputKind(kDynamicExecutable), 
+       : fOutputFile("a.out"), fArchitecture(0), fSubArchitecture(0), fArchitectureName("unknown"), fOutputKind(kDynamicExecutable), 
          fHasPreferredSubType(false), fPrebind(false), fBindAtLoad(false), fKeepPrivateExterns(false),
          fNeedsModuleTable(false), fIgnoreOtherArchFiles(false), fErrorOnOtherArchFiles(false), fForceSubtypeAll(false), 
-         fInterposeMode(kInterposeNone), fDeadStrip(kDeadStripOff), fNameSpace(kTwoLevelNameSpace),
-         fDylibCompatVersion(0), fDylibCurrentVersion(0), fDylibInstallName(NULL), fFinalName(NULL), fEntryName("start"), fBaseAddress(0),
+         fInterposeMode(kInterposeNone), fDeadStrip(false), fNameSpace(kTwoLevelNameSpace),
+         fDylibCompatVersion(0), fDylibCurrentVersion(0), fDylibInstallName(NULL), fFinalName(NULL), fEntryName("start"), 
+         fBaseAddress(0), fMaxAddress(0x7FFFFFFFFFFFFFFFLL), 
          fBaseWritableAddress(0), fSplitSegs(false),
-         fExportMode(kExportDefault), fLibrarySearchMode(kSearchAllDirsForDylibsThenAllDirsForArchives),
-         fUndefinedTreatment(kUndefinedError), fMessagesPrefixedWithArchitecture(false), 
+         fExportMode(kExportDefault), fLibrarySearchMode(kSearchDylibAndArchiveInEachDir),
+         fUndefinedTreatment(kUndefinedError), fMessagesPrefixedWithArchitecture(true), 
          fWeakReferenceMismatchTreatment(kWeakReferenceMismatchNonWeak),
          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), 
+         fNonExecutableHeap(false), fDisableNonExecutableHeap(false),
          fMinimumHeaderPad(32), fSegmentAlignment(4096), 
          fCommonsMode(kCommonsIgnoreDylibs),  fUUIDMode(kUUIDContent), fLocalSymbolHandling(kLocalSymbolsAll), fWarnCommons(false), 
          fVerbose(false), fKeepRelocations(false), fWarnStabs(false),
          fTraceDylibSearching(false), fPause(false), fStatistics(false), fPrintOptions(false),
          fSharedRegionEligible(false), fPrintOrderFileStatistics(false),  
-         fReadOnlyx86Stubs(false), fPositionIndependentExecutable(false), 
+         fReadOnlyx86Stubs(false), fPositionIndependentExecutable(false), fPIEOnCommandLine(false),
          fDisablePositionIndependentExecutable(false), fMaxMinimumHeaderPad(false),
          fDeadStripDylibs(false),  fAllowTextRelocs(false), fWarnTextRelocs(false), 
          fUsingLazyDylibLinking(false), fEncryptable(true), 
          fOrderData(true), fMarkDeadStrippableDylib(false),
-         fMakeClassicDyldInfo(true), fMakeCompressedDyldInfo(true), fAllowCpuSubtypeMismatches(false),
-         fUseSimplifiedDylibReExports(false), fObjCABIVersion2POverride(false), fSaveTempFiles(false)
+         fMakeCompressedDyldInfo(true), fMakeCompressedDyldInfoForceOff(false), fNoEHLabels(false),
+         fAllowCpuSubtypeMismatches(false), fUseSimplifiedDylibReExports(false),
+         fObjCABIVersion2Override(false), fObjCABIVersion1Override(false), fCanUseUpwardDylib(false),
+         fFullyLoadArchives(false), fLoadAllObjcObjectsFromArchives(false), fFlatNamespace(false),
+         fLinkingMainExecutable(false), fForFinalLinkedImage(false), fForStatic(false),
+         fForDyld(false), fMakeTentativeDefinitionsReal(false), fWhyLoad(false), fRootSafe(false),
+         fSetuidSafe(false), fImplicitlyLinkPublicDylibs(true), fAddCompactUnwindEncoding(true),
+         fWarnCompactUnwind(false), fRemoveDwarfUnwindIfCompactExists(false),
+         fAutoOrderInitializers(true), fOptimizeZeroFill(true), fLogObjectFiles(false),
+         fLogAllFiles(false), fTraceDylibs(false), fTraceIndirectDylibs(false), fTraceArchives(false),
+         fOutputSlidable(false), fWarnWeakExports(false), 
+         fObjcGcCompaction(false), fObjCGc(false), fObjCGcOnly(false), 
+         fDemangle(false), fTLVSupport(false), 
+#if __MAC_OS_X_VERSION_MIN_REQUIRED < 1070
+         fVersionLoadCommand(false), fFunctionStartsLoadCommand(false),
+#else
+         fVersionLoadCommand(true), fFunctionStartsLoadCommand(true),
+#endif
+         fCanReExportSymbols(false), fObjcCategoryMerging(true), 
+         fDebugInfoStripping(kDebugInfoMinimal), fTraceOutputFile(NULL), 
+         fMacVersionMin(ld::macVersionUnset), fIPhoneVersionMin(ld::iPhoneVersionUnset), 
+         fSaveTempFiles(false)
 {
        this->checkForClassic(argc, argv);
        this->parsePreCommandLineEnvironmentSettings();
@@ -119,48 +147,10 @@ Options::~Options()
 {
 }
 
-const ObjectFile::ReaderOptions& Options::readerOptions()
-{
-       return fReaderOptions;
-}
-
-
-const char*    Options::getOutputFilePath()
-{
-       return fOutputFile;
-}
-
-std::vector<Options::FileInfo>& Options::getInputFiles()
-{
-       return fInputFiles;
-}
-
-Options::OutputKind    Options::outputKind()
-{
-       return fOutputKind;
-}
 
-bool Options::bindAtLoad()
-{
-       return fBindAtLoad;
-}
 
-bool Options::prebind()
-{
-       return fPrebind;
-}
 
-bool Options::fullyLoadArchives()
-{
-       return fReaderOptions.fFullyLoadArchives;
-}
-
-Options::NameSpace Options::nameSpace()
-{
-       return fNameSpace;
-}
-
-const char*    Options::installPath()
+const char*    Options::installPath() const
 {
        if ( fDylibInstallName != NULL )
                return fDylibInstallName;
@@ -170,32 +160,8 @@ const char*        Options::installPath()
                return fOutputFile;
 }
 
-uint32_t Options::currentVersion()
-{
-       return fDylibCurrentVersion;
-}
-
-uint32_t Options::compatibilityVersion()
-{
-       return fDylibCompatVersion;
-}
-
-const char*    Options::entryName()
-{
-       return fEntryName;
-}
-
-uint64_t Options::baseAddress()
-{
-       return fBaseAddress;
-}
-
-bool Options::keepPrivateExterns()
-{
-       return fKeepPrivateExterns;
-}
 
-bool Options::interposable(const char* name)
+bool Options::interposable(const char* name) const
 {
        switch ( fInterposeMode ) {
                case kInterposeNone:
@@ -208,121 +174,34 @@ bool Options::interposable(const char* name)
        throw "internal error";
 }
 
-bool Options::needsModuleTable()
-{
-       return fNeedsModuleTable;
-}
-
-bool Options::ignoreOtherArchInputFiles()
-{
-       return fIgnoreOtherArchFiles;
-}
-
-bool Options::forceCpuSubtypeAll()
-{
-       return fForceSubtypeAll;
-}
-
-bool Options::traceDylibs()
-{
-       return fReaderOptions.fTraceDylibs;
-}
-
-bool Options::traceArchives()
-{
-       return fReaderOptions.fTraceArchives;
-}
-
-Options::UndefinedTreatment Options::undefinedTreatment()
-{
-       return fUndefinedTreatment;
-}
-
-Options::WeakReferenceMismatchTreatment        Options::weakReferenceMismatchTreatment()
-{
-       return fWeakReferenceMismatchTreatment;
-}
-
-const char* Options::umbrellaName()
-{
-       return fUmbrellaName;
-}
-
-std::vector<const char*>& Options::allowableClients()
-{
-       return fAllowableClients;
-}
-
-const char* Options::clientName()
-{
-       return fClientName;
-}
-
-uint64_t Options::zeroPageSize()
-{
-       return fZeroPageSize;
-}
-
-bool Options::hasCustomStack()
-{
-       return (fStackSize != 0);
-}
-
-uint64_t Options::customStackSize()
-{
-       return fStackSize;
-}
-
-uint64_t Options::customStackAddr()
-{
-       return fStackAddr;
-}
 
-bool Options::hasExecutableStack()
-{
-       return fExecutableStack;
-}
 
-std::vector<const char*>& Options::initialUndefines()
-{
-       return fInitialUndefines;
-}
 
-bool Options::printWhyLive(const char* symbolName)
+bool Options::printWhyLive(const char* symbolName) const
 {
        return ( fWhyLive.find(symbolName) != fWhyLive.end() );
 }
 
 
-const char*    Options::initFunctionName()
-{
-       return fInitFunctionName;
-}
-
 const char*    Options::dotOutputFile()
 {
        return fDotOutputFile;
 }
 
-bool Options::hasExportRestrictList()
-{
-       return (fExportMode != kExportDefault);
-}
 
-bool Options::hasExportMaskList()
+bool Options::hasWildCardExportRestrictList() const
 {
-       return (fExportMode == kExportSome);
+       // has -exported_symbols_list which contains some wildcards
+       return ((fExportMode == kExportSome) && fExportSymbols.hasWildCards());
 }
 
-
-bool Options::hasWildCardExportRestrictList()
+bool Options::hasWeakBitTweaks() const
 {
        // has -exported_symbols_list which contains some wildcards
-       return ((fExportMode == kExportSome) && fExportSymbols.hasWildCards());
+       return (!fForceWeakSymbols.empty() || !fForceNotWeakSymbols.empty());
 }
 
-
-bool Options::allGlobalsAreDeadStripRoots()
+bool Options::allGlobalsAreDeadStripRoots() const
 {
        // -exported_symbols_list means globals are not exported by default
        if ( fExportMode == kExportSome )
@@ -344,59 +223,122 @@ bool Options::allGlobalsAreDeadStripRoots()
        return false;
 }
 
-uint32_t Options::minimumHeaderPad()
+
+bool Options::keepRelocations()
 {
-       return fMinimumHeaderPad;
+       return fKeepRelocations;
 }
 
-std::vector<Options::ExtraSection>&    Options::extraSections()
+bool Options::warnStabs()
 {
-       return fExtraSections;
+       return fWarnStabs;
 }
 
-std::vector<Options::SectionAlignment>&        Options::sectionAlignments()
+const char* Options::executablePath()
 {
-       return fSectionAlignments;
+       return fExecutablePath;
 }
 
-Options::CommonsMode Options::commonsMode()
+
+uint32_t Options::initialSegProtection(const char* segName) const
 {
-       return fCommonsMode;
+       for(std::vector<Options::SegmentProtect>::const_iterator it = fCustomSegmentProtections.begin(); it != fCustomSegmentProtections.end(); ++it) {
+               if ( strcmp(it->name, segName) == 0 ) {
+                       return it->init;
+               }
+       }
+       if ( strcmp(segName, "__PAGEZERO") == 0 ) {
+               return 0;
+       }
+       else if ( strcmp(segName, "__TEXT") == 0 ) {
+               return VM_PROT_READ | VM_PROT_EXECUTE;
+       }
+       else if ( strcmp(segName, "__LINKEDIT") == 0 ) {
+               return VM_PROT_READ;
+       }
+       
+       // all others default to read-write
+       return VM_PROT_READ | VM_PROT_WRITE;
 }
 
-bool Options::warnCommons()
+uint32_t Options::maxSegProtection(const char* segName) const
 {
-       return fWarnCommons;
+       // iPhoneOS always uses same protection for max and initial
+       if ( fIPhoneVersionMin != ld::iPhoneVersionUnset ) 
+               return initialSegProtection(segName);
+
+       for(std::vector<Options::SegmentProtect>::const_iterator it = fCustomSegmentProtections.begin(); it != fCustomSegmentProtections.end(); ++it) {
+               if ( strcmp(it->name, segName) == 0 ) {
+                       return it->max;
+               }
+       }
+       if ( strcmp(segName, "__PAGEZERO") == 0 ) {
+               return 0;
+       }
+       // all others default to all
+       return VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
+}
+       
+uint64_t Options::segPageSize(const char* segName) const
+{
+       for(std::vector<SegmentSize>::const_iterator it=fCustomSegmentSizes.begin(); it != fCustomSegmentSizes.end(); ++it) {
+               if ( strcmp(it->name, segName) == 0 )
+                       return it->size;
+       }
+       return fSegmentAlignment;
 }
 
-bool Options::keepRelocations()
+uint64_t Options::customSegmentAddress(const char* segName) const
 {
-       return fKeepRelocations;
+       for(std::vector<SegmentStart>::const_iterator it=fCustomSegmentAddresses.begin(); it != fCustomSegmentAddresses.end(); ++it) {
+               if ( strcmp(it->name, segName) == 0 )
+                       return it->address;
+       }
+       // if custom stack in use, model as segment with custom address
+       if ( (fStackSize != 0) && (strcmp("__UNIXSTACK", segName) == 0) )
+               return fStackAddr - fStackSize;
+       return 0;
 }
 
-bool Options::warnStabs()
+bool Options::hasCustomSegmentAddress(const char* segName) const
 {
-       return fWarnStabs;
+       for(std::vector<SegmentStart>::const_iterator it=fCustomSegmentAddresses.begin(); it != fCustomSegmentAddresses.end(); ++it) {
+               if ( strcmp(it->name, segName) == 0 )
+                       return true;
+       }
+       // if custom stack in use, model as segment with custom address
+       if ( (fStackSize != 0) && (strcmp("__UNIXSTACK", segName) == 0) )
+               return true;
+       return false;
 }
 
-const char* Options::executablePath()
+bool Options::hasCustomSectionAlignment(const char* segName, const char* sectName) const
 {
-       return fExecutablePath;
+       for (std::vector<SectionAlignment>::const_iterator it = fSectionAlignments.begin(); it != fSectionAlignments.end(); ++it) {
+               if ( (strcmp(it->segmentName, segName) == 0) && (strcmp(it->sectionName, sectName) == 0) )
+                       return true;
+       }
+       return false;
 }
 
-Options::DeadStripMode Options::deadStrip()
+uint8_t Options::customSectionAlignment(const char* segName, const char* sectName) const
 {
-       return fDeadStrip;
+       for (std::vector<SectionAlignment>::const_iterator it = fSectionAlignments.begin(); it != fSectionAlignments.end(); ++it) {
+               if ( (strcmp(it->segmentName, segName) == 0) && (strcmp(it->sectionName, sectName) == 0) )
+                       return it->alignment;
+       }
+       return 0;
 }
 
+
 bool Options::hasExportedSymbolOrder()
 {
        return (fExportSymbolsOrder.size() > 0);
 }
 
-bool Options::exportedSymbolOrder(const char* sym, unsigned int* order)
+bool Options::exportedSymbolOrder(const char* sym, unsigned int* order) const
 {
-       NameToOrder::iterator pos = fExportSymbolsOrder.find(sym);
+       NameToOrder::const_iterator pos = fExportSymbolsOrder.find(sym);
        if ( pos != fExportSymbolsOrder.end() ) {
                *order = pos->second;
                return true;
@@ -478,8 +420,28 @@ void Options::loadSymbolOrderFile(const char* fileOfExports, NameToOrder& orderM
        // Note: we do not free() the malloc buffer, because the strings are used by the export-set hash table
 }
 
+bool Options::forceWeak(const char* symbolName) const
+{
+       return fForceWeakSymbols.contains(symbolName);
+}
+
+bool Options::forceNotWeak(const char* symbolName) const
+{
+       return fForceNotWeakSymbols.contains(symbolName);
+}
+
+bool Options::forceWeakNonWildCard(const char* symbolName) const
+{
+       return fForceWeakSymbols.containsNonWildcard(symbolName);
+}
+
+bool Options::forceNotWeakNonWildcard(const char* symbolName) const
+{
+       return fForceNotWeakSymbols.containsNonWildcard(symbolName);
+}
+
 
-bool Options::shouldExport(const char* symbolName)
+bool Options::shouldExport(const char* symbolName) const
 {
        switch (fExportMode) {
                case kExportSome:
@@ -492,7 +454,12 @@ bool Options::shouldExport(const char* symbolName)
        throw "internal error";
 }
 
-bool Options::keepLocalSymbol(const char* symbolName)
+bool Options::shouldReExport(const char* symbolName) const
+{
+       return fReExportSymbols.contains(symbolName);
+}
+
+bool Options::keepLocalSymbol(const char* symbolName) const
 {
        switch (fLocalSymbolHandling) {
                case kLocalSymbolsAll:
@@ -507,81 +474,204 @@ bool Options::keepLocalSymbol(const char* symbolName)
        throw "internal error";
 }
 
-void Options::parseArch(const char* architecture)
+
+void Options::setArchitecture(cpu_type_t type, cpu_subtype_t subtype)
 {
-       if ( architecture == NULL )
+       fArchitecture = type;
+       fSubArchitecture = subtype;
+       switch ( type ) {
+       case CPU_TYPE_POWERPC:
+               switch ( subtype ) {
+               case CPU_SUBTYPE_POWERPC_750:
+                       fArchitectureName = "ppc750";
+                       fHasPreferredSubType = true;
+                       break;
+               case CPU_SUBTYPE_POWERPC_7400:
+                       fArchitectureName = "ppc7400";
+                       fHasPreferredSubType = true;
+                       break;
+               case CPU_SUBTYPE_POWERPC_7450:
+                       fArchitectureName = "ppc7450";
+                       fHasPreferredSubType = true;
+                       break;
+               case CPU_SUBTYPE_POWERPC_970:
+                       fArchitectureName = "ppc970";
+                       fHasPreferredSubType = true;
+                       break;
+               case CPU_SUBTYPE_POWERPC_ALL:
+                       fArchitectureName = "ppc";
+                       fHasPreferredSubType = false;
+                       break;
+               default:
+                       assert(0 && "unknown ppc subtype");
+                       fArchitectureName = "ppc";
+                       break;
+               }
+               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          
+               }
+               break;
+       case CPU_TYPE_POWERPC64:
+               fArchitectureName = "ppc64";
+               if ( (fMacVersionMin == ld::macVersionUnset) && (fOutputKind != Options::kObjectFile) ) {
+                       warning("-macosx_version_min not specificed, assuming 10.5");
+                       fMacVersionMin = ld::mac10_5;
+               }
+               break;
+       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:
+               switch ( subtype ) {
+               case CPU_SUBTYPE_ARM_V4T:
+                       fArchitectureName = "armv4t";
+                       fHasPreferredSubType = true;
+                       break;
+               case CPU_SUBTYPE_ARM_V5TEJ:
+                       fArchitectureName = "armv5";
+                       fHasPreferredSubType = true;
+                       break;
+               case CPU_SUBTYPE_ARM_V6:
+                       fArchitectureName = "armv6";
+                       fHasPreferredSubType = true;
+                       break;
+               case CPU_SUBTYPE_ARM_V7:
+                       fArchitectureName = "armv7";
+                       fHasPreferredSubType = true;
+                       break;
+               default:
+                       assert(0 && "unknown arm subtype");
+                       fArchitectureName = "arm";
+                       break;
+               }
+               if ( (fMacVersionMin == ld::macVersionUnset) && (fIPhoneVersionMin == ld::iPhoneVersionUnset) && (fOutputKind != Options::kObjectFile) ) {
+#if defined(DEFAULT_IPHONEOS_MIN_VERSION)
+                       warning("-ios_version_min not specificed, assuming " DEFAULT_IPHONEOS_MIN_VERSION);
+                       setIPhoneVersionMin(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::iPhone3_1) && !fMakeCompressedDyldInfoForceOff )
+                       fMakeCompressedDyldInfo = true;
+               break;
+       default:
+               fArchitectureName = "unknown architecture";
+               break;
+       }
+}
+
+void Options::parseArch(const char* arch)
+{
+       if ( arch == NULL )
                throw "-arch must be followed by an architecture string";
-       if ( strcmp(architecture, "ppc") == 0 ) {
+       fArchitectureName = arch;
+       if ( strcmp(arch, "ppc") == 0 ) {
                fArchitecture = CPU_TYPE_POWERPC;
                fSubArchitecture = CPU_SUBTYPE_POWERPC_ALL;
        }
-       else if ( strcmp(architecture, "ppc64") == 0 ) {
+       else if ( strcmp(arch, "ppc64") == 0 ) {
                fArchitecture = CPU_TYPE_POWERPC64;
                fSubArchitecture = CPU_SUBTYPE_POWERPC_ALL;
        }
-       else if ( strcmp(architecture, "i386") == 0 ) {
+       else if ( strcmp(arch, "i386") == 0 ) {
                fArchitecture = CPU_TYPE_I386;
                fSubArchitecture = CPU_SUBTYPE_I386_ALL;
        }
-       else if ( strcmp(architecture, "x86_64") == 0 ) {
+       else if ( strcmp(arch, "x86_64") == 0 ) {
                fArchitecture = CPU_TYPE_X86_64;
                fSubArchitecture = CPU_SUBTYPE_X86_64_ALL;
        }
-       else if ( strcmp(architecture, "arm") == 0 ) {
+       else if ( strcmp(arch, "arm") == 0 ) {
                fArchitecture = CPU_TYPE_ARM;
                fSubArchitecture = CPU_SUBTYPE_ARM_ALL;
        }
        // compatibility support for cpu-sub-types
-       else if ( strcmp(architecture, "ppc750") == 0 ) {
+       else if ( strcmp(arch, "ppc750") == 0 ) {
                fArchitecture = CPU_TYPE_POWERPC;
                fSubArchitecture = CPU_SUBTYPE_POWERPC_750;
                fHasPreferredSubType = true;
        }
-       else if ( strcmp(architecture, "ppc7400") == 0 ) {
+       else if ( strcmp(arch, "ppc7400") == 0 ) {
                fArchitecture = CPU_TYPE_POWERPC;
                fSubArchitecture = CPU_SUBTYPE_POWERPC_7400;
                fHasPreferredSubType = true;
        }
-       else if ( strcmp(architecture, "ppc7450") == 0 ) {
+       else if ( strcmp(arch, "ppc7450") == 0 ) {
                fArchitecture = CPU_TYPE_POWERPC;
                fSubArchitecture = CPU_SUBTYPE_POWERPC_7450;
                fHasPreferredSubType = true;
        }
-       else if ( strcmp(architecture, "ppc970") == 0 ) {
+       else if ( strcmp(arch, "ppc970") == 0 ) {
                fArchitecture = CPU_TYPE_POWERPC;
                fSubArchitecture = CPU_SUBTYPE_POWERPC_970;
                fHasPreferredSubType = true;
        }
-       else if ( strcmp(architecture, "armv6") == 0 ) {
+       else if ( strcmp(arch, "armv6") == 0 ) {
                fArchitecture = CPU_TYPE_ARM;
                fSubArchitecture = CPU_SUBTYPE_ARM_V6;
                fHasPreferredSubType = true;
        }
-       else if ( strcmp(architecture, "armv5") == 0 ) {
+       else if ( strcmp(arch, "armv5") == 0 ) {
                fArchitecture = CPU_TYPE_ARM;
                fSubArchitecture = CPU_SUBTYPE_ARM_V5TEJ;
                fHasPreferredSubType = true;
        }
-       else if ( strcmp(architecture, "armv4t") == 0 ) {
+       else if ( strcmp(arch, "armv4t") == 0 ) {
                fArchitecture = CPU_TYPE_ARM;
                fSubArchitecture = CPU_SUBTYPE_ARM_V4T;
                fHasPreferredSubType = true;
        }
-       else if ( strcmp(architecture, "xscale") == 0 ) {
+       else if ( strcmp(arch, "xscale") == 0 ) {
                fArchitecture = CPU_TYPE_ARM;
                fSubArchitecture = CPU_SUBTYPE_ARM_XSCALE;
                fHasPreferredSubType = true;
        }
-       else if ( strcmp(architecture, "armv7") == 0 ) {
+       else if ( strcmp(arch, "armv7") == 0 ) {
                fArchitecture = CPU_TYPE_ARM;
                fSubArchitecture = CPU_SUBTYPE_ARM_V7;
                fHasPreferredSubType = true;
        }
        else
-               throwf("unknown/unsupported architecture name for: -arch %s", architecture);
+               throwf("unknown/unsupported architecture name for: -arch %s", arch);
 }
 
-bool Options::checkForFile(const char* format, const char* dir, const char* rootName, FileInfo& result)
+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];
@@ -723,7 +813,7 @@ Options::FileInfo Options::findFramework(const char* rootName, const char* suffi
                throwf("framework not found %s", rootName);
 }
 
-Options::FileInfo Options::findFile(const char* path)
+Options::FileInfo Options::findFile(const char* path) const
 {
        FileInfo result;
        struct stat statBuffer;
@@ -731,7 +821,7 @@ Options::FileInfo Options::findFile(const char* path)
        // if absolute path and not a .o file, the use SDK prefix
        if ( (path[0] == '/') && (strcmp(&path[strlen(path)-2], ".o") != 0) ) {
                const int pathLen = strlen(path);
-               for (std::vector<const char*>::iterator it = fSDKPaths.begin(); it != fSDKPaths.end(); it++) {
+               for (std::vector<const char*>::const_iterator it = fSDKPaths.begin(); it != fSDKPaths.end(); it++) {
                        // ??? Shouldn't we be using String here?
                        const char* sdkPathDir = *it;
                        const int sdkPathDirLen = strlen(sdkPathDir);
@@ -777,7 +867,7 @@ Options::FileInfo Options::findFile(const char* path)
        throwf("file not found: %s", path);
 }
 
-Options::FileInfo Options::findFileUsingPaths(const char* path)
+Options::FileInfo Options::findFileUsingPaths(const char* path) const 
 {
        FileInfo result;
 
@@ -803,7 +893,7 @@ Options::FileInfo Options::findFileUsingPaths(const char* path)
        // don't need to try variations, just paths. We do need to add the additional bits
        // onto the framework path though.
        if ( isFramework ) {
-               for (std::vector<const char*>::iterator it = fFrameworkSearchPaths.begin();
+               for (std::vector<const char*>::const_iterator it = fFrameworkSearchPaths.begin();
                         it != fFrameworkSearchPaths.end();
                         it++) {
                        const char* dir = *it;
@@ -826,7 +916,7 @@ Options::FileInfo Options::findFileUsingPaths(const char* path)
                                        && (strcmp(&leafName[leafLen-6], ".dylib") == 0) 
                                        && (strstr(path, ".framework/") != NULL) );
                if ( !embeddedDylib ) {
-                       for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin();
+                       for (std::vector<const char*>::const_iterator it = fLibrarySearchPaths.begin();
                                 it != fLibrarySearchPaths.end();
                                 it++) {
                                const char* dir = *it;
@@ -842,7 +932,7 @@ Options::FileInfo Options::findFileUsingPaths(const char* path)
 }
  
 
-void Options::parseSegAddrTable(const char* segAddrPath, const char* installPath)
+void Options::parseSegAddrTable(const char* segAddrPath, const char* installPth)
 {
        FILE* file = fopen(segAddrPath, "r");
        if ( file == NULL ) {
@@ -879,7 +969,7 @@ void Options::parseSegAddrTable(const char* segAddrPath, const char* installPath
                                for(char* end = eol-1; (end > p) && isspace(*end); --end)
                                        *end = '\0';
                                // see if this line is for the dylib being linked
-                               if ( strcmp(p, installPath) == 0 ) {
+                               if ( strcmp(p, installPth) == 0 ) {
                                        fBaseAddress = firstColumAddress;
                                        if ( hasSecondColumn ) {
                                                fBaseWritableAddress = secondColumAddress;
@@ -939,7 +1029,18 @@ void Options::loadFileList(const char* fileOfPaths)
        fclose(file);
 }
 
-bool Options::SetWithWildcards::hasWildCards(const char* symbol)
+
+void Options::SetWithWildcards::remove(const NameSet& toBeRemoved)
+{
+       for(NameSet::const_iterator it=toBeRemoved.begin(); it != toBeRemoved.end(); ++it) {
+               const char* symbolName = *it;
+               NameSet::iterator pos = fRegular.find(symbolName);
+               if ( pos != fRegular.end() )
+                       fRegular.erase(pos);
+       }
+}
+
+bool Options::SetWithWildcards::hasWildCards(const char* symbol) 
 {
        // an exported symbol name containing *, ?, or [ requires wildcard matching
        return ( strpbrk(symbol, "*?[") != NULL );
@@ -953,21 +1054,28 @@ void Options::SetWithWildcards::insert(const char* symbol)
                fRegular.insert(symbol);
 }
 
-bool Options::SetWithWildcards::contains(const char* symbol)
+bool Options::SetWithWildcards::contains(const char* symbol) const
 {
        // first look at hash table on non-wildcard symbols
        if ( fRegular.find(symbol) != fRegular.end() )
                return true;
        // next walk list of wild card symbols looking for a match
-       for(std::vector<const char*>::iterator it = fWildCard.begin(); it != fWildCard.end(); ++it) {
+       for(std::vector<const char*>::const_iterator it = fWildCard.begin(); it != fWildCard.end(); ++it) {
                if ( wildCardMatch(*it, symbol) )
                        return true;
        }
        return false;
 }
 
+bool Options::SetWithWildcards::containsNonWildcard(const char* symbol) const
+{
+       // look at hash table on non-wildcard symbols
+       return ( fRegular.find(symbol) != fRegular.end() );
+}
+
+
 
-bool Options::SetWithWildcards::inCharRange(const char*& p, unsigned char c)
+bool Options::SetWithWildcards::inCharRange(const char*& p, unsigned char c) const
 {
        ++p; // find end
        const char* b = p;
@@ -996,7 +1104,7 @@ bool Options::SetWithWildcards::inCharRange(const char*& p, unsigned char c)
        return false;
 }
 
-bool Options::SetWithWildcards::wildCardMatch(const char* pattern, const char* symbol)
+bool Options::SetWithWildcards::wildCardMatch(const char* pattern, const char* symbol) const
 {
        const char* s = symbol;
        for (const char* p = pattern; *p != '\0'; ++p) {
@@ -1031,6 +1139,8 @@ bool Options::SetWithWildcards::wildCardMatch(const char* pattern, const char* s
 
 void Options::loadExportFile(const char* fileOfExports, const char* option, SetWithWildcards& set)
 {
+       if ( fileOfExports == NULL )
+               throwf("missing file after %s", option);
        // read in whole file
        int fd = ::open(fileOfExports, O_RDONLY, 0);
        if ( fd == -1 )
@@ -1117,7 +1227,7 @@ void Options::parseAliasFile(const char* fileOfAliases)
        ::close(fd);
 
        // parse into symbols and add to fAliases
-       ObjectFile::ReaderOptions::AliasPair pair;
+       AliasPair pair;
        char * const end = &p[stat_buf.st_size+1];
        enum { lineStart, inRealName, inBetween, inAliasName, inComment } state = lineStart;
        int lineNumber = 1;
@@ -1163,7 +1273,7 @@ void Options::parseAliasFile(const char* fileOfAliases)
                                        *last = '\0';
                                        --last;
                                }
-                               fReaderOptions.fAliases.push_back(pair);
+                               fAliases.push_back(pair);
                                state = inComment;
                        }
                        else if ( *s == '\n' ) {
@@ -1174,7 +1284,7 @@ void Options::parseAliasFile(const char* fileOfAliases)
                                        *last = '\0';
                                        --last;
                                }
-                               fReaderOptions.fAliases.push_back(pair);
+                               fAliases.push_back(pair);
                                state = lineStart;
                        }
                        break;
@@ -1228,34 +1338,8 @@ void Options::setMacOSXVersionMin(const char* version)
                throw "-macosx_version_min argument missing";
 
        if ( (strncmp(version, "10.", 3) == 0) && isdigit(version[3]) ) {
-               int num = version[3] - '0';
-               switch ( num ) {
-                       case 0:
-                       case 1:
-                               fReaderOptions.fMacVersionMin = ObjectFile::ReaderOptions::k10_1;
-                               break;
-                       case 2:
-                               fReaderOptions.fMacVersionMin = ObjectFile::ReaderOptions::k10_2;
-                               break;
-                       case 3:
-                               fReaderOptions.fMacVersionMin = ObjectFile::ReaderOptions::k10_3;
-                               break;
-                       case 4:
-                               fReaderOptions.fMacVersionMin = ObjectFile::ReaderOptions::k10_4;
-                               break;
-                       case 5:
-                               fReaderOptions.fMacVersionMin = ObjectFile::ReaderOptions::k10_5;
-                               break;
-                       case 6:
-                               fReaderOptions.fMacVersionMin = ObjectFile::ReaderOptions::k10_6;
-                               break;
-                       case 7:
-                               fReaderOptions.fMacVersionMin = ObjectFile::ReaderOptions::k10_7;
-                               break;
-                       default:
-                               fReaderOptions.fMacVersionMin = ObjectFile::ReaderOptions::k10_7;
-                               break;
-                       }
+               unsigned int minorVersion = version[3] - '0';
+               fMacVersionMin = (ld::MacVersionMin)(0x000A0000 | (minorVersion << 8));
        }
        else {
                warning("unknown option to -macosx_version_min, not 10.x");
@@ -1265,41 +1349,26 @@ void Options::setMacOSXVersionMin(const char* version)
 void Options::setIPhoneVersionMin(const char* version)
 {
        if ( version == NULL )
-               throw "-iphoneos_version_min argument missing";
+               throw "-ios_version_min argument missing";
        if ( ! isdigit(version[0]) )
-               throw "-iphoneos_version_min argument is not a number";
+               throw "-ios_version_min argument is not a number";
        if ( version[1] != '.' )
-               throw "-iphoneos_version_min argument is missing period as second character";
+               throw "-ios_version_min argument is missing period as second character";
        if ( ! isdigit(version[2]) )
-               throw "-iphoneos_version_min argument is not a number";
-
-                if ( (version[0] == '2') && (version[2] == '0') )
-               fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k2_0;
-       else if ( (version[0] == '2') && (version[2] == '1') )
-               fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k2_1;
-       else if ( (version[0] == '2') && (version[2] >= '2') )
-               fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k2_2;
-       else if ( (version[0] == '3') && (version[2] == '0') )
-               fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k3_0;
-       else if ( (version[0] == '3') && (version[2] == '1') )
-               fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k3_1;
-       else if ( (version[0] == '3') && (version[2] >= '2') )
-               fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k3_2;
-       else if ( (version[0] >= '4')  )
-               fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k4_0;
-       else {
-               fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k2_0;
-               warning("unknown option to -iphoneos_version_min, not 2.x, 3.x, or 4.x");
-       }
+               throw "-ios_version_min argument is not a number";
+
+       unsigned int majorVersion = version[0] - '0';
+       unsigned int minorVersion = version[2] - '0';
+       fIPhoneVersionMin = (ld::IPhoneVersionMin)((majorVersion << 16) | (minorVersion << 8));
 }
 
-bool Options::minOS(ObjectFile::ReaderOptions::MacVersionMin requiredMacMin, ObjectFile::ReaderOptions::IPhoneVersionMin requirediPhoneOSMin)
+bool Options::minOS(ld::MacVersionMin requiredMacMin, ld::IPhoneVersionMin requirediPhoneOSMin)
 {
-       if ( fReaderOptions.fMacVersionMin != ObjectFile::ReaderOptions::kMinMacVersionUnset ) {
-               return ( fReaderOptions.fMacVersionMin >= requiredMacMin );
+       if ( fMacVersionMin != ld::macVersionUnset ) {
+               return ( fMacVersionMin >= requiredMacMin );
        }
        else {
-               return ( fReaderOptions.fIPhoneVersionMin >= requirediPhoneOSMin);
+               return ( fIPhoneVersionMin >= requirediPhoneOSMin);
        }
 }
 
@@ -1488,7 +1557,7 @@ static const char* cstringSymbolName(const char* orderFileString)
 void Options::parseOrderFile(const char* path, bool cstring)
 {
        // order files override auto-ordering
-       fReaderOptions.fAutoOrderInitializers = false;
+       fAutoOrderInitializers = false;
 
        // read in whole file
        int fd = ::open(path, O_RDONLY, 0);
@@ -1721,6 +1790,8 @@ void Options::parse(int argc, const char* argv[])
                                fprintf (stderr, "[Logging ld64 options]\t%s\n", arg);
 
                        if ( (arg[1] == 'L') || (arg[1] == 'F') ) {
+                               if (arg[2] == '\0')
+                                       ++i;
                                // previously handled by buildSearchPaths()
                        }
                        // The one gnu style option we have to keep compatibility
@@ -1737,8 +1808,8 @@ void Options::parse(int argc, const char* argv[])
                                // default
                        }
                        else if ( strcmp(arg, "-static") == 0 ) {
-                               fReaderOptions.fForStatic = true;
-                               if ( fOutputKind != kObjectFile ) {
+                               fForStatic = true;
+                               if ( (fOutputKind != kObjectFile) && (fOutputKind != kKextBundle) ) {
                                        fOutputKind = kStaticExecutable;
                                }
                        }
@@ -1767,6 +1838,12 @@ void Options::parse(int argc, const char* argv[])
                        else if ( strcmp(arg, "-o") == 0 ) {
                                fOutputFile = argv[++i];
                        }
+                       else if ( strncmp(arg, "-lazy-l", 7) == 0 ) {
+                               FileInfo info = findLibrary(&arg[7], true);
+                               info.options.fLazyLoad = true;
+                               addLibrary(info);
+                               fUsingLazyDylibLinking = true;
+                       }
                        else if ( (arg[1] == 'l') && (strncmp(arg,"-lazy_",6) !=0) ) {
                                addLibrary(findLibrary(&arg[2]));
                        }
@@ -1777,14 +1854,7 @@ void Options::parse(int argc, const char* argv[])
                                info.options.fWeakImport = true;
                                addLibrary(info);
                        }
-                       else if ( strncmp(arg, "-lazy-l", 7) == 0 ) {
-                               FileInfo info = findLibrary(&arg[7], true);
-                               info.options.fLazyLoad = true;
-                               addLibrary(info);
-                               fUsingLazyDylibLinking = true;
-                       }
                        // Avoid lazy binding.
-                       // ??? Deprecate.
                        else if ( strcmp(arg, "-bind_at_load") == 0 ) {
                                fBindAtLoad = true;
                        }
@@ -1802,14 +1872,14 @@ void Options::parse(int argc, const char* argv[])
                        }
                        // Similar to --whole-archive.
                        else if ( strcmp(arg, "-all_load") == 0 ) {
-                               fReaderOptions.fFullyLoadArchives = true;
+                               fFullyLoadArchives = true;
                        }
                        else if ( strcmp(arg, "-noall_load") == 0) {
                                warnObsolete(arg);
                        }
                        // Similar to -all_load
                        else if ( strcmp(arg, "-ObjC") == 0 ) {
-                               fReaderOptions.fLoadAllObjcObjectsFromArchives = true;
+                               fLoadAllObjcObjectsFromArchives = true;
                        }
                        // Similar to -all_load, but for the following archive only.
                        else if ( strcmp(arg, "-force_load") == 0 ) {
@@ -1981,6 +2051,9 @@ void Options::parse(int argc, const char* argv[])
                        else if ( strcmp(arg, "-search_paths_first") == 0 ) {
                                // previously handled by buildSearchPaths()
                        }
+                       else if ( strcmp(arg, "-search_dylibs_first") == 0 ) {
+                               // previously handled by buildSearchPaths()
+                       }
                        else if ( strcmp(arg, "-undefined") == 0 ) {
                                 setUndefinedTreatment(argv[++i]);
                        }
@@ -2148,6 +2221,9 @@ void Options::parse(int argc, const char* argv[])
                        else if ( strcmp(arg, "-allow_stack_execute") == 0 ) {
                                fExecutableStack = true;
                        }
+                       else if ( strcmp(arg, "-allow_heap_execute") == 0 ) {
+                               fDisableNonExecutableHeap = true;
+                       }
                        else if ( strcmp(arg, "-sectalign") == 0 ) {
                                 if ( (argv[i+1]==NULL) || (argv[i+2]==NULL) || (argv[i+3]==NULL) )
                                        throw "-sectalign missing <segment> <section> <file-path>";
@@ -2179,7 +2255,7 @@ void Options::parse(int argc, const char* argv[])
                        else if ( strcmp(arg, "-macosx_version_min") == 0 ) {
                                setMacOSXVersionMin(argv[++i]);
                        }
-                       else if ( strcmp(arg, "-iphoneos_version_min") == 0 ) {
+                       else if ( (strcmp(arg, "-iphoneos_version_min") == 0) || (strcmp(arg, "-ios_version_min") == 0) ) {
                                setIPhoneVersionMin(argv[++i]);
                        }
                        else if ( strcmp(arg, "-multiply_defined") == 0 ) {
@@ -2209,7 +2285,7 @@ void Options::parse(int argc, const char* argv[])
                                warnObsolete(arg);
                        }
                        else if ( (strcmp(arg, "-why_load") == 0) || (strcmp(arg, "-whyload") == 0) ) {
-                                fReaderOptions.fWhyLoad = true;
+                                fWhyLoad = true;
                        }
                        else if ( strcmp(arg, "-why_live") == 0 ) {
                                 const char* name = argv[++i];
@@ -2232,36 +2308,36 @@ void Options::parse(int argc, const char* argv[])
                        else if ( strcmp(arg, "-s") == 0 ) {
                                warnObsolete(arg);
                                fLocalSymbolHandling = kLocalSymbolsNone;
-                               fReaderOptions.fDebugInfoStripping = ObjectFile::ReaderOptions::kDebugInfoNone;
+                               fDebugInfoStripping = Options::kDebugInfoNone;
                        }
                        else if ( strcmp(arg, "-x") == 0 ) {
                                fLocalSymbolHandling = kLocalSymbolsNone;
                        }
                        else if ( strcmp(arg, "-S") == 0 ) {
-                               fReaderOptions.fDebugInfoStripping = ObjectFile::ReaderOptions::kDebugInfoNone;
+                               fDebugInfoStripping = Options::kDebugInfoNone;
                        }
                        else if ( strcmp(arg, "-X") == 0 ) {
                                warnObsolete(arg);
                        }
                        else if ( strcmp(arg, "-Si") == 0 ) {
                                warnObsolete(arg);
-                               fReaderOptions.fDebugInfoStripping = ObjectFile::ReaderOptions::kDebugInfoFull;
+                               fDebugInfoStripping = Options::kDebugInfoFull;
                        }
                        else if ( strcmp(arg, "-b") == 0 ) {
                                warnObsolete(arg);
                        }
                        else if ( strcmp(arg, "-Sn") == 0 ) {
                                warnObsolete(arg);
-                               fReaderOptions.fDebugInfoStripping = ObjectFile::ReaderOptions::kDebugInfoFull;
+                               fDebugInfoStripping = Options::kDebugInfoFull;
                        }
                        else if ( strcmp(arg, "-Sp") == 0 ) {
                                warnObsolete(arg);
                        }
                        else if ( strcmp(arg, "-dead_strip") == 0 ) {
-                               fDeadStrip = kDeadStripOnPlusUnusedInits;
+                               fDeadStrip = true;
                        }
                        else if ( strcmp(arg, "-no_dead_strip_inits_and_terms") == 0 ) {
-                               fDeadStrip = kDeadStripOn;
+                               fDeadStrip = true;
                        }
                        else if ( strcmp(arg, "-w") == 0 ) {
                                // previously handled by buildSearchPaths()
@@ -2282,10 +2358,10 @@ void Options::parse(int argc, const char* argv[])
                                fMaxMinimumHeaderPad = true;
                        }
                        else if ( strcmp(arg, "-t") == 0 ) {
-                               fReaderOptions.fLogAllFiles = true;
+                               fLogAllFiles = true;
                        }
                        else if ( strcmp(arg, "-whatsloaded") == 0 ) {
-                               fReaderOptions.fLogObjectFiles = true;
+                               fLogObjectFiles = true;
                        }
                        else if ( strcmp(arg, "-A") == 0 ) {
                                warnObsolete(arg);
@@ -2356,7 +2432,7 @@ void Options::parse(int argc, const char* argv[])
                                fStatistics = true;
                        }
                        else if ( strcmp(arg, "-d") == 0 ) {
-                               fReaderOptions.fMakeTentativeDefinitionsReal = true;
+                               fMakeTentativeDefinitionsReal = true;
                        }
                        else if ( strcmp(arg, "-v") == 0 ) {
                                // previously handled by buildSearchPaths()
@@ -2381,20 +2457,20 @@ void Options::parse(int argc, const char* argv[])
                                fDtraceScriptName = name;
                        }
                        else if ( strcmp(arg, "-root_safe") == 0 ) {
-                               fReaderOptions.fRootSafe = true;
+                               fRootSafe = true;
                        }
                        else if ( strcmp(arg, "-setuid_safe") == 0 ) {
-                               fReaderOptions.fSetuidSafe = true;
+                               fSetuidSafe = true;
                        }
                        else if ( strcmp(arg, "-alias") == 0 ) {
-                               ObjectFile::ReaderOptions::AliasPair pair;
+                               Options::AliasPair pair;
                                pair.realName = argv[++i];
                                if ( pair.realName == NULL )
                                        throw "missing argument to -alias";
                                pair.alias = argv[++i];
                                if ( pair.alias == NULL )
                                        throw "missing argument to -alias";
-                               fReaderOptions.fAliases.push_back(pair);
+                               fAliases.push_back(pair);
                        }
                        else if ( strcmp(arg, "-alias_list") == 0 ) {
                                parseAliasFile(argv[++i]);
@@ -2404,12 +2480,12 @@ void Options::parse(int argc, const char* argv[])
                                const char* colon = strchr(arg, ':');
                                if ( colon == NULL )
                                        throwf("unknown option: %s", arg);
-                               ObjectFile::ReaderOptions::AliasPair pair;
+                               Options::AliasPair pair;
                                char* temp = new char[colon-arg];
                                strlcpy(temp, &arg[2], colon-arg-1);
                                pair.realName = &colon[1];
                                pair.alias = temp;
-                               fReaderOptions.fAliases.push_back(pair);
+                               fAliases.push_back(pair);
                        }
                        else if ( strcmp(arg, "-save-temps") == 0 ) {
                                fSaveTempFiles = true;
@@ -2433,6 +2509,7 @@ void Options::parse(int argc, const char* argv[])
                        }
                        else if ( strcmp(arg, "-pie") == 0 ) {
                                fPositionIndependentExecutable = true;
+                               fPIEOnCommandLine = true;
                        }
                        else if ( strcmp(arg, "-no_pie") == 0 ) {
                                fDisablePositionIndependentExecutable = true;
@@ -2452,11 +2529,26 @@ void Options::parse(int argc, const char* argv[])
                                info.options.fReExport = true;
                                addLibrary(info);
                        }
+                       else if ( strncmp(arg, "-upward-l", 9) == 0 ) {
+                               FileInfo info = findLibrary(&arg[9], true);
+                               info.options.fUpward = true;
+                               addLibrary(info);
+                       }
+                       else if ( strcmp(arg, "-upward_library") == 0 ) {
+                               FileInfo info = findFile(argv[++i]);
+                               info.options.fUpward = true;
+                               addLibrary(info);
+                       }
+                       else if ( strcmp(arg, "-upward_framework") == 0 ) {
+                               FileInfo info = findFramework(argv[++i]);
+                               info.options.fUpward = true;
+                               addLibrary(info);
+                       }
                        else if ( strcmp(arg, "-dead_strip_dylibs") == 0 ) {
                                fDeadStripDylibs = true;
                        }
                        else if ( strcmp(arg, "-no_implicit_dylibs") == 0 ) {
-                               fReaderOptions.fImplicitlyLinkPublicDylibs = false;
+                               fImplicitlyLinkPublicDylibs = false;
                        }
                        else if ( strcmp(arg, "-new_linker") == 0 ) {
                                // ignore
@@ -2465,7 +2557,7 @@ void Options::parse(int argc, const char* argv[])
                                fEncryptable = false;
                        }
                        else if ( strcmp(arg, "-no_compact_unwind") == 0 ) {
-                               fReaderOptions.fAddCompactUnwindEncoding = false;
+                               fAddCompactUnwindEncoding = false;
                        }
                        else if ( strcmp(arg, "-mllvm") == 0 ) {
                                const char* opts = argv[++i];
@@ -2474,7 +2566,7 @@ void Options::parse(int argc, const char* argv[])
                                fLLVMOptions.push_back(opts);
                        }
                        else if ( strcmp(arg, "-no_order_inits") == 0 ) {
-                               fReaderOptions.fAutoOrderInitializers = false;
+                               fAutoOrderInitializers = false;
                        }
                        else if ( strcmp(arg, "-no_order_data") == 0 ) {
                                fOrderData = false;
@@ -2498,30 +2590,108 @@ void Options::parse(int argc, const char* argv[])
                        }
                        else if ( strcmp(arg, "-no_compact_linkedit") == 0 ) {
                                fMakeCompressedDyldInfo = false;
+                               fMakeCompressedDyldInfoForceOff = true;
                        }
                        else if ( strcmp(arg, "-no_eh_labels") == 0 ) {
-                               fReaderOptions.fNoEHLabels = true;
+                               fNoEHLabels = true;
                        }
                        else if ( strcmp(arg, "-warn_compact_unwind") == 0 ) {
-                               fReaderOptions.fWarnCompactUnwind = true;
+                               fWarnCompactUnwind = true;
                        }
                        else if ( strcmp(arg, "-allow_sub_type_mismatches") == 0 ) {
                                fAllowCpuSubtypeMismatches = true;
                        }
                        else if ( strcmp(arg, "-no_zero_fill_sections") == 0 ) {
-                               fReaderOptions.fOptimizeZeroFill = false;
+                               fOptimizeZeroFill = false;
                        }
                        else if ( strcmp(arg, "-objc_abi_version") == 0 ) {
                                const char* version = argv[++i];
                                 if ( version == NULL )
                                        throw "-objc_abi_version missing version number";
-                               if ( strcmp(version, "2") == 0 )
-                                       fObjCABIVersion2POverride = true;
+                               if ( strcmp(version, "2") == 0 ) {
+                                       fObjCABIVersion1Override = false;
+                                       fObjCABIVersion2Override = true;
+                               }
+                               else if ( strcmp(version, "1") == 0 ) {
+                                       fObjCABIVersion1Override = true;
+                                       fObjCABIVersion2Override = false;
+                               }
                                else
                                        warning("ignoring unrecognized argument (%s) to -objc_abi_version", version);
                        }
+                       else if ( strcmp(arg, "-warn_weak_exports") == 0 ) {
+                               fWarnWeakExports = true;
+                       }
+                       else if ( strcmp(arg, "-objc_gc_compaction") == 0 ) {
+                               fObjcGcCompaction = true;
+                       }
+                       else if ( strcmp(arg, "-objc_gc") == 0 ) {
+                               fObjCGc = true;
+                               if ( fObjCGcOnly ) { 
+                                       warning("-objc_gc overriding -objc_gc_only");
+                                       fObjCGcOnly = false;    
+                               }
+                       }
+                       else if ( strcmp(arg, "-objc_gc_only") == 0 ) {
+                               fObjCGcOnly = true;
+                               if ( fObjCGc ) { 
+                                       warning("-objc_gc_only overriding -objc_gc");
+                                       fObjCGc = false;        
+                               }
+                       }
                        else if ( strcmp(arg, "-demangle") == 0 ) {
-                               // <rdar://problem/8303976> add -demangle noop to ld64-97
+                               fDemangle = true;
+                       }
+                       else if ( strcmp(arg, "-version_load_command") == 0 ) {
+                               fVersionLoadCommand = true;
+                       }
+                       else if ( strcmp(arg, "-no_version_load_command") == 0 ) {
+                               fVersionLoadCommand = false;
+                       }
+                       else if ( strcmp(arg, "-function_starts") == 0 ) {
+                               fFunctionStartsLoadCommand = true;
+                       }
+                       else if ( strcmp(arg, "-no_function_starts") == 0 ) {
+                               fFunctionStartsLoadCommand = false;
+                       }
+                       else if ( strcmp(arg, "-object_path_lto") == 0 ) {
+                               fTempLtoObjectPath = argv[++i];
+                               if ( fTempLtoObjectPath == NULL )
+                                       throw "missing argument to -object_path_lto";
+                       }
+                       else if ( strcmp(arg, "-no_objc_category_merging") == 0 ) {
+                               fObjcCategoryMerging = false;
+                       }
+                       else if ( strcmp(arg, "-force_symbols_weak_list") == 0 ) {
+                               loadExportFile(argv[++i], "-force_symbols_weak_list", fForceWeakSymbols);
+                       }
+                       else if ( strcmp(arg, "-force_symbols_not_weak_list") == 0 ) {
+                               loadExportFile(argv[++i], "-force_symbols_not_weak_list", fForceNotWeakSymbols);
+                       }
+                       else if ( strcmp(arg, "-force_symbol_weak") == 0 ) {
+                               const char* symbol = argv[++i];
+                               if ( symbol == NULL )
+                                       throw "-force_symbol_weak missing <symbol>";
+                               fForceWeakSymbols.insert(symbol);
+                       }
+                       else if ( strcmp(arg, "-force_symbol_not_weak") == 0 ) {
+                               const char* symbol = argv[++i];
+                               if ( symbol == NULL )
+                                       throw "-force_symbol_not_weak missing <symbol>";
+                               fForceNotWeakSymbols.insert(symbol);
+                       }
+                       else if ( strcmp(arg, "-reexported_symbols_list") == 0 ) {
+                               if ( fExportMode == kExportSome )
+                                       throw "can't use -exported_symbols_list and -reexported_symbols_list";
+                               loadExportFile(argv[++i], "-reexported_symbols_list", fReExportSymbols);
+                       }
+                       else if ( strcmp(arg, "-dyld_env") == 0 ) {
+                               const char* envarg = argv[++i];
+                               if ( envarg == NULL )
+                                       throw "-dyld_env missing ENV=VALUE";
+                               if ( strchr(envarg, '=') == NULL )
+                                       throw "-dyld_env missing ENV=VALUE";
+                               fDyldEnvironExtras.push_back(envarg);
                        }
                        else {
                                throwf("unknown option: %s", arg);
@@ -2564,6 +2734,14 @@ void Options::buildSearchPaths(int argc, const char* argv[])
        for(int i=0; i < argc; ++i) {
                if ( (argv[i][0] == '-') && (argv[i][1] == 'L') ) {
                        const char* libSearchDir = &argv[i][2];
+                       // Allow either "-L{path}" or "-L {path}".
+                       if (argv[i][2] == '\0') {
+                               // -L {path}.  Make sure there is an argument following this.
+                               const char* path = argv[++i];
+                               if ( path == NULL )
+                                       throw "-L missing argument";
+                               libSearchDir = path;
+                       }
                        if ( libSearchDir[0] == '\0' ) 
                                throw "-L must be immediately followed by a directory path (no space)";
                        struct stat statbuf;
@@ -2574,11 +2752,19 @@ void Options::buildSearchPaths(int argc, const char* argv[])
                                        warning("path '%s' following -L not a directory", libSearchDir);
                        }
                        else {
-                               warning("directory '%s' following -L not found", libSearchDir);
+                               warning("directory not found for option '-L%s'", libSearchDir);
                        }
                }
                else if ( (argv[i][0] == '-') && (argv[i][1] == 'F') ) {
                        const char* frameworkSearchDir = &argv[i][2];
+                       // Allow either "-F{path}" or "-F {path}".
+                       if (argv[i][2] == '\0') {
+                               // -F {path}.  Make sure there is an argument following this.
+                               const char* path = argv[++i];
+                               if ( path == NULL )
+                                       throw "-F missing argument";
+                               frameworkSearchDir = path;
+                       }
                        if ( frameworkSearchDir[0] == '\0' ) 
                                throw "-F must be immediately followed by a directory path (no space)";
                        struct stat statbuf;
@@ -2589,7 +2775,7 @@ void Options::buildSearchPaths(int argc, const char* argv[])
                                        warning("path '%s' following -F not a directory", frameworkSearchDir);
                        }
                        else {
-                               warning("directory '%s' following -F not found", frameworkSearchDir);
+                               warning("directory not found for option '-F%s'", frameworkSearchDir);
                        }
                }
                else if ( strcmp(argv[i], "-Z") == 0 )
@@ -2600,9 +2786,9 @@ void Options::buildSearchPaths(int argc, const char* argv[])
                        fprintf(stderr, "%s", ldVersionString);
                         // if only -v specified, exit cleanly
                         if ( argc == 2 ) {
-#if LTO_SUPPORT
-                               printLTOVersion(*this);
-#endif
+                               const char* ltoVers = lto::version();
+                               if ( ltoVers != NULL )
+                                       fprintf(stderr, "%s\n", ltoVers);
                                exit(0);
                        }
                }
@@ -2613,9 +2799,11 @@ void Options::buildSearchPaths(int argc, const char* argv[])
                        fSDKPaths.push_back(path);
                }
                else if ( strcmp(argv[i], "-search_paths_first") == 0 ) {
-                       // ??? Deprecate when we get -Bstatic/-Bdynamic.
                        fLibrarySearchMode = kSearchDylibAndArchiveInEachDir;
                }
+               else if ( strcmp(argv[i], "-search_dylibs_first") == 0 ) {
+                       fLibrarySearchMode = kSearchAllDirsForDylibsThenAllDirsForArchives;
+               }
                else if ( strcmp(argv[i], "-w") == 0 ) {
                        sEmitWarnings = false;
                }
@@ -2736,12 +2924,12 @@ void Options::parsePreCommandLineEnvironmentSettings()
 {
        if ((getenv("LD_TRACE_ARCHIVES") != NULL)
                || (getenv("RC_TRACE_ARCHIVES") != NULL))
-           fReaderOptions.fTraceArchives = true;
+           fTraceArchives = true;
 
        if ((getenv("LD_TRACE_DYLIBS") != NULL)
                || (getenv("RC_TRACE_DYLIBS") != NULL)) {
-           fReaderOptions.fTraceDylibs = true;
-               fReaderOptions.fTraceIndirectDylibs = true;
+           fTraceDylibs = true;
+               fTraceIndirectDylibs = true;
        }
 
        if (getenv("RC_TRACE_DYLIB_SEARCHING") != NULL) {
@@ -2751,8 +2939,8 @@ void Options::parsePreCommandLineEnvironmentSettings()
        if (getenv("LD_PRINT_OPTIONS") != NULL)
                fPrintOptions = true;
 
-       if (fReaderOptions.fTraceDylibs || fReaderOptions.fTraceArchives)
-               fReaderOptions.fTraceOutputFile = getenv("LD_TRACE_FILE");
+       if (fTraceDylibs || fTraceArchives)
+               fTraceOutputFile = getenv("LD_TRACE_FILE");
 
        if (getenv("LD_PRINT_ORDER_FILE_STATISTICS") != NULL)
                fPrintOrderFileStatistics = true;
@@ -2769,15 +2957,14 @@ void Options::parsePreCommandLineEnvironmentSettings()
        // for now disable compressed linkedit functionality
        if ( getenv("LD_NO_COMPACT_LINKEDIT") != NULL ) {
                fMakeCompressedDyldInfo = false;
-               fMakeClassicDyldInfo = true;
-       }
-       // temporary until projects adopt -no_pie
-       if ( getenv("LD_NO_PIE") != NULL ) {
-               warning("LD_NO_PIE being used to disble building a position independent executable");
-               fDisablePositionIndependentExecutable = true;
+               fMakeCompressedDyldInfoForceOff = true;
        }
 
        sWarningsSideFilePath = getenv("LD_WARN_FILE");
+       
+       const char* customDyldPath = getenv("LD_DYLD_PATH");
+       if ( customDyldPath != NULL ) 
+               fDyldInstallPath = customDyldPath;
 }
 
 
@@ -2799,13 +2986,13 @@ void Options::parsePostCommandLineEnvironmentSettings()
        }
        
        // allow build system to force on dead-code-stripping
-       if ( fDeadStrip == kDeadStripOff ) {
+       if ( !fDeadStrip ) {
                if ( getenv("LD_DEAD_STRIP") != NULL ) {
                        switch (fOutputKind) {
                                case Options::kDynamicLibrary:
                                case Options::kDynamicExecutable:
                                case Options::kDynamicBundle:
-                                       fDeadStrip = kDeadStripOn;
+                                       fDeadStrip = true;
                                        break;
                                case Options::kPreload:
                                case Options::kObjectFile:
@@ -2828,48 +3015,73 @@ void Options::reconfigureDefaults()
        // sync reader options
        switch ( fOutputKind ) {
                case Options::kObjectFile:
-                       fReaderOptions.fForFinalLinkedImage = false;
+                       fForFinalLinkedImage = false;
                        break;
                case Options::kDyld:
-                       fReaderOptions.fForDyld = true;
-                       fReaderOptions.fForFinalLinkedImage = true;
-                       fReaderOptions.fNoEHLabels = true;
+                       fForDyld = true;
+                       fForFinalLinkedImage = true;
+                       fNoEHLabels = true;
                        break;
                case Options::kDynamicLibrary:
                case Options::kDynamicBundle:
                case Options::kKextBundle:
-                       fReaderOptions.fForFinalLinkedImage = true;
-                       fReaderOptions.fNoEHLabels = true;
+                       fForFinalLinkedImage = true;
+                       fNoEHLabels = true;
                        break;
                case Options::kDynamicExecutable:
                case Options::kStaticExecutable:
                case Options::kPreload:
-                       fReaderOptions.fLinkingMainExecutable = true;
-                       fReaderOptions.fForFinalLinkedImage = true;
-                       fReaderOptions.fNoEHLabels = true;
+                       fLinkingMainExecutable = true;
+                       fForFinalLinkedImage = true;
+                       fNoEHLabels = true;
                        break;
        }
 
        // set default min OS version
-       if ( (fReaderOptions.fMacVersionMin == ObjectFile::ReaderOptions::kMinMacVersionUnset)
-               && (fReaderOptions.fIPhoneVersionMin == ObjectFile::ReaderOptions::kMinIPhoneVersionUnset) ) {
+       if ( (fMacVersionMin == ld::macVersionUnset)
+               && (fIPhoneVersionMin == ld::iPhoneVersionUnset) ) {
                // if neither -macosx_version_min nor -iphoneos_version_min used, try environment variables
                const char* macVers = getenv("MACOSX_DEPLOYMENT_TARGET");
                const char* iPhoneVers = getenv("IPHONEOS_DEPLOYMENT_TARGET");
+               const char* iOSVers = getenv("IOS_DEPLOYMENT_TARGET");
                if ( macVers != NULL ) 
                        setMacOSXVersionMin(macVers);
                else if ( iPhoneVers != NULL )
                        setIPhoneVersionMin(iPhoneVers);
+               else if ( iOSVers != NULL )
+                       setIPhoneVersionMin(iOSVers);
                else {
                        // if still nothing, set default based on architecture
                        switch ( fArchitecture ) {
                                case CPU_TYPE_I386:
                                case CPU_TYPE_X86_64:
                                case CPU_TYPE_POWERPC:                  
-                                       fReaderOptions.fMacVersionMin = ObjectFile::ReaderOptions::k10_6; // FIX FIX, this really should be a check of the OS version the linker is running o
+                                       if ( (fOutputKind != Options::kObjectFile) && (fOutputKind != Options::kPreload) ) {
+                       #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          
+                                       }
                                        break;
                                case CPU_TYPE_ARM:
-                                       fReaderOptions.fIPhoneVersionMin = ObjectFile::ReaderOptions::k2_0; 
+                                       if ( (fOutputKind != Options::kObjectFile) && (fOutputKind != Options::kPreload) ) {
+                       #if defined(DEFAULT_IPHONEOS_MIN_VERSION)
+                                               warning("-ios_version_min not specificed, assuming " DEFAULT_IPHONEOS_MIN_VERSION);
+                                               setIPhoneVersionMin(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
+                                       }
+                                       break;
+                               default:
+                                       // architecture will be infered ;ater by examining .o files
                                        break;
                        }
                }
@@ -2879,21 +3091,21 @@ void Options::reconfigureDefaults()
        // adjust min based on architecture
        switch ( fArchitecture ) {
                case CPU_TYPE_I386:
-                       if ( fReaderOptions.fMacVersionMin < ObjectFile::ReaderOptions::k10_4 ) {
+                       if ( (fMacVersionMin < ld::mac10_4) && (fIPhoneVersionMin == ld::iPhoneVersionUnset) ) {
                                //warning("-macosx_version_min should be 10.4 or later for i386");
-                               fReaderOptions.fMacVersionMin = ObjectFile::ReaderOptions::k10_4;
+                               fMacVersionMin = ld::mac10_4;
                        }
                        break;
                case CPU_TYPE_POWERPC64:
-                       if ( fReaderOptions.fMacVersionMin < ObjectFile::ReaderOptions::k10_4 ) {
+                       if ( fMacVersionMin < ld::mac10_4 ) {
                                //warning("-macosx_version_min should be 10.4 or later for ppc64");
-                               fReaderOptions.fMacVersionMin = ObjectFile::ReaderOptions::k10_4;
+                               fMacVersionMin = ld::mac10_4;
                        }
                        break;
                case CPU_TYPE_X86_64:
-                       if ( fReaderOptions.fMacVersionMin < ObjectFile::ReaderOptions::k10_4 ) {
+                       if ( fMacVersionMin < ld::mac10_4 ) {
                                //warning("-macosx_version_min should be 10.4 or later for x86_64");
-                               fReaderOptions.fMacVersionMin = ObjectFile::ReaderOptions::k10_4;
+                               fMacVersionMin = ld::mac10_4;
                        }
                        break;
        }
@@ -2903,8 +3115,8 @@ void Options::reconfigureDefaults()
                switch ( fArchitecture ) {
                        case CPU_TYPE_X86_64:
                                // x86_64 uses new MH_KEXT_BUNDLE type
-                               fMakeClassicDyldInfo = true; 
                                fMakeCompressedDyldInfo = false;
+                               fMakeCompressedDyldInfoForceOff = true;
                                fAllowTextRelocs = true;
                                fUndefinedTreatment = kUndefinedDynamicLookup;
                                break;
@@ -2919,8 +3131,8 @@ void Options::reconfigureDefaults()
 
        // disable implicit dylibs when targeting 10.3
        // <rdar://problem/5451987> add option to disable implicit load commands for indirectly used public dylibs
-       if ( !minOS(ObjectFile::ReaderOptions::k10_4, ObjectFile::ReaderOptions::k2_0) )
-               fReaderOptions.fImplicitlyLinkPublicDylibs = false;
+       if ( !minOS(ld::mac10_4, ld::iPhone2_0) )
+               fImplicitlyLinkPublicDylibs = false;
 
 
        // allow build system to force linker to ignore -prebind
@@ -2979,6 +3191,39 @@ void Options::reconfigureDefaults()
                }
        }
 
+       // set too-large size
+       switch ( fArchitecture ) {
+               case CPU_TYPE_POWERPC:
+               case CPU_TYPE_I386:
+                       fMaxAddress = 0xFFFFFFFF;
+                       break;
+               case CPU_TYPE_POWERPC64:
+               case CPU_TYPE_X86_64:
+                       break;
+               case CPU_TYPE_ARM:
+                       switch ( fOutputKind ) {
+                               case Options::kDynamicExecutable:
+                               case Options::kDynamicLibrary:
+                               case Options::kDynamicBundle:
+                                       // user land code is limited to low 1GB
+                                       fMaxAddress = 0x2FFFFFFF;
+                                       break;
+                               case Options::kStaticExecutable:
+                               case Options::kObjectFile:
+                               case Options::kDyld:
+                               case Options::kPreload:
+                               case Options::kKextBundle:
+                                       fMaxAddress = 0xFFFFFFFF;
+                                       break;
+                       }
+                       // range check -seg1addr for ARM
+                       if ( fBaseAddress > fMaxAddress ) {
+                               warning("ignoring -seg1addr 0x%08llX.  Address out of range.", fBaseAddress);
+                               fBaseAddress = 0;
+                       }
+                       break;
+       }
+
        // <rdar://problem/6138961> -r implies no prebinding for all architectures
        if ( fOutputKind == Options::kObjectFile )
                fPrebind = false;                       
@@ -2988,12 +3233,12 @@ void Options::reconfigureDefaults()
                switch ( fArchitecture ) {
                        case CPU_TYPE_POWERPC:
                        case CPU_TYPE_I386:
-                               if ( fReaderOptions.fMacVersionMin == ObjectFile::ReaderOptions::k10_4 ) {
+                               if ( fMacVersionMin == ld::mac10_4 ) {
                                        // in 10.4 only split seg dylibs are prebound
                                        if ( (fOutputKind != Options::kDynamicLibrary) || ! fSplitSegs )
                                                fPrebind = false;
                                }
-                               else if ( fReaderOptions.fMacVersionMin >= ObjectFile::ReaderOptions::k10_5 ) {
+                               else if ( fMacVersionMin >= ld::mac10_5 ) {
                                        // in 10.5 nothing is prebound
                                        fPrebind = false;
                                }
@@ -3046,7 +3291,7 @@ void Options::reconfigureDefaults()
 
        // determine if info for shared region should be added
        if ( fOutputKind == Options::kDynamicLibrary ) {
-               if ( minOS(ObjectFile::ReaderOptions::k10_5, ObjectFile::ReaderOptions::k3_1) )
+               if ( minOS(ld::mac10_5, ld::iPhone3_1) )
                        if ( !fPrebind )
                                if ( (strncmp(this->installPath(), "/usr/lib/", 9) == 0)
                                        || (strncmp(this->installPath(), "/System/Library/", 16) == 0) )
@@ -3058,7 +3303,7 @@ void Options::reconfigureDefaults()
                switch ( fArchitecture ) {
                        case CPU_TYPE_POWERPC:  // 10.3 and earlier dyld requires a module table
                        case CPU_TYPE_I386:             // ld_classic for 10.4.x requires a module table
-                               if ( fReaderOptions.fMacVersionMin <= ObjectFile::ReaderOptions::k10_5 )
+                               if ( fMacVersionMin <= ld::mac10_5 )
                                        fNeedsModuleTable = true;
                                break;
                        case CPU_TYPE_ARM:
@@ -3070,7 +3315,7 @@ void Options::reconfigureDefaults()
        
        // <rdar://problem/5366363> -r -x implies -S
        if ( (fOutputKind == Options::kObjectFile) && (fLocalSymbolHandling == kLocalSymbolsNone) )
-               fReaderOptions.fDebugInfoStripping = ObjectFile::ReaderOptions::kDebugInfoNone;                 
+               fDebugInfoStripping = Options::kDebugInfoNone;                  
                
        // choose how to process unwind info
        switch ( fArchitecture ) {
@@ -3081,26 +3326,26 @@ void Options::reconfigureDefaults()
                                case Options::kStaticExecutable:
                                case Options::kPreload:
                                case Options::kKextBundle:
-                                       fReaderOptions.fAddCompactUnwindEncoding = false;
+                                       fAddCompactUnwindEncoding = false;
                                        break;
                                case Options::kDyld:
                                case Options::kDynamicLibrary:
                                case Options::kDynamicBundle:
                                case Options::kDynamicExecutable:
-                                       //if ( fReaderOptions.fAddCompactUnwindEncoding && (fReaderOptions.fVersionMin >= ObjectFile::ReaderOptions::k10_6) )
-                                       //      fReaderOptions.fRemoveDwarfUnwindIfCompactExists = true;
+                                       //if ( fAddCompactUnwindEncoding && (fVersionMin >= ld::mac10_6) )
+                                       //      fRemoveDwarfUnwindIfCompactExists = true;
                                        break;
                        }
                        break;
                case CPU_TYPE_POWERPC:
                case CPU_TYPE_POWERPC64:                
                case CPU_TYPE_ARM:
-                       fReaderOptions.fAddCompactUnwindEncoding = false;
-                       fReaderOptions.fRemoveDwarfUnwindIfCompactExists = false;
+                       fAddCompactUnwindEncoding = false;
+                       fRemoveDwarfUnwindIfCompactExists = false;
                        break;
                case 0:
                        // if -arch is missing, assume we don't want compact unwind info
-                       fReaderOptions.fAddCompactUnwindEncoding = false;
+                       fAddCompactUnwindEncoding = false;
                        break;
        }
                
@@ -3113,7 +3358,7 @@ void Options::reconfigureDefaults()
        // don't move inits in dyld because dyld wants certain
        // entries point at stable locations at the start of __text
        if ( fOutputKind == Options::kDyld ) 
-               fReaderOptions.fAutoOrderInitializers = false;
+               fAutoOrderInitializers = false;
                
                
        // disable __data ordering for some output kinds
@@ -3131,6 +3376,24 @@ void Options::reconfigureDefaults()
                        break;
        }
        
+       // only use compressed LINKEDIT for final linked images
+       switch ( fOutputKind ) {
+               case Options::kDynamicExecutable:
+               case Options::kDynamicLibrary:
+               case Options::kDynamicBundle:
+                       break;
+               case Options::kPreload:
+               case Options::kStaticExecutable:
+               case Options::kObjectFile:
+               case Options::kDyld:
+               case Options::kKextBundle:
+                       fMakeCompressedDyldInfoForceOff = true;
+                       break;
+       }
+       if ( fMakeCompressedDyldInfoForceOff ) 
+               fMakeCompressedDyldInfo = false;
+
+       
        // only use compressed LINKEDIT for:
        //                      x86_64 and i386 on Mac OS X 10.6 or later
        //                      arm on iPhoneOS 3.1 or later
@@ -3138,15 +3401,11 @@ void Options::reconfigureDefaults()
                switch (fArchitecture) {
                        case CPU_TYPE_I386:
                        case CPU_TYPE_X86_64:
-                               if ( fReaderOptions.fMacVersionMin >= ObjectFile::ReaderOptions::k10_6 ) 
-                                       fMakeClassicDyldInfo = false; 
-                               else if ( fReaderOptions.fMacVersionMin < ObjectFile::ReaderOptions::k10_5 )
+                               if ( fMacVersionMin < ld::mac10_6 ) 
                                        fMakeCompressedDyldInfo = false;
                                break;
             case CPU_TYPE_ARM:
-                               if ( fReaderOptions.fIPhoneVersionMin >= ObjectFile::ReaderOptions::k3_1 ) 
-                                       fMakeClassicDyldInfo = false; 
-                               else if ( fReaderOptions.fIPhoneVersionMin < ObjectFile::ReaderOptions::k3_1 )
+                               if ( !minOS(ld::mac10_6, ld::iPhone3_1) )
                                        fMakeCompressedDyldInfo = false;
                                break;
                        case CPU_TYPE_POWERPC:
@@ -3155,25 +3414,7 @@ void Options::reconfigureDefaults()
                                fMakeCompressedDyldInfo = false;
                }
        }
-       
 
-       // only use compressed LINKEDIT for final linked images
-       if ( fMakeCompressedDyldInfo ) {
-               switch ( fOutputKind ) {
-                       case Options::kDynamicExecutable:
-                       case Options::kDynamicLibrary:
-                       case Options::kDynamicBundle:
-                               break;
-                       case Options::kPreload:
-                       case Options::kStaticExecutable:
-                       case Options::kObjectFile:
-                       case Options::kDyld:
-                       case Options::kKextBundle:
-                               fMakeCompressedDyldInfo = false;
-                               break;
-               }
-       }
-       fReaderOptions.fMakeCompressedDyldInfo = fMakeCompressedDyldInfo;
                
        // only ARM enforces that cpu-sub-types must match
        if ( fArchitecture != CPU_TYPE_ARM )
@@ -3181,7 +3422,11 @@ void Options::reconfigureDefaults()
                
        // only final linked images can not optimize zero fill sections
        if ( fOutputKind == Options::kObjectFile )
-               fReaderOptions.fOptimizeZeroFill = true;
+               fOptimizeZeroFill = true;
+
+       // all undefines in -r mode
+//     if ( fOutputKind == Options::kObjectFile )
+//             fUndefinedTreatment = kUndefinedSuppress;
 
        // only dynamic final linked images should warn about use of commmons
        if ( fWarnCommons ) {
@@ -3201,14 +3446,95 @@ void Options::reconfigureDefaults()
        }
        
        // Mac OS X 10.5 and iPhoneOS 2.0 support LC_REEXPORT_DYLIB
-       if ( minOS(ObjectFile::ReaderOptions::k10_5, ObjectFile::ReaderOptions::k2_0) )
+       if ( minOS(ld::mac10_5, ld::iPhone2_0) )
                fUseSimplifiedDylibReExports = true;
+       
+       // Mac OS X 10.7 and iOS 4.2 support LC_LOAD_UPWARD_DYLIB
+       if ( minOS(ld::mac10_7, ld::iPhone4_2) && (fOutputKind == kDynamicLibrary) )
+               fCanUseUpwardDylib = true;
                
        // x86_64 for MacOSX 10.7 defaults to PIE
-       if ( (fArchitecture == CPU_TYPE_X86_64) && (fOutputKind == kDynamicExecutable)
-                       && (fReaderOptions.fMacVersionMin >= ObjectFile::ReaderOptions::k10_7) ) {
+       if ( (fArchitecture == CPU_TYPE_X86_64) && (fOutputKind == kDynamicExecutable) && (fMacVersionMin >= ld::mac10_7) ) {
                fPositionIndependentExecutable = true;
        }
+
+       // armv7 for iOS4.3 defaults to PIE
+       if ( (fArchitecture == CPU_TYPE_ARM) 
+               && (fSubArchitecture == CPU_SUBTYPE_ARM_V7)
+               && (fOutputKind == kDynamicExecutable) 
+               && (fIPhoneVersionMin >= ld::iPhone4_3) ) {
+                       fPositionIndependentExecutable = true;
+       }
+
+       // -no_pie anywhere on command line disable PIE
+       if ( fDisablePositionIndependentExecutable )
+               fPositionIndependentExecutable = false;
+
+       // set fOutputSlidable
+       switch ( fOutputKind ) {
+               case Options::kObjectFile:
+               case Options::kStaticExecutable:
+                       fOutputSlidable = false;
+                       break;
+               case Options::kDynamicExecutable:
+                       fOutputSlidable = fPositionIndependentExecutable;
+                       break;
+               case Options::kPreload:
+                       fOutputSlidable = fPIEOnCommandLine;
+                       break;
+               case Options::kDyld:
+               case Options::kDynamicLibrary:
+               case Options::kDynamicBundle:
+               case Options::kKextBundle:
+                       fOutputSlidable = true;
+                       break;
+       }
+
+       // let linker know if thread local variables are supported
+       if ( fMacVersionMin >= ld::mac10_7 ) {
+               fTLVSupport = true;
+       }
+       
+       // version load command is only in some kinds of output files
+       switch ( fOutputKind ) {
+               case Options::kObjectFile:
+               case Options::kStaticExecutable:
+               case Options::kPreload:
+               case Options::kKextBundle:
+                       fVersionLoadCommand = false;
+                       fFunctionStartsLoadCommand = false;
+                       break;
+               case Options::kDynamicExecutable:
+               case Options::kDyld:
+               case Options::kDynamicLibrary:
+               case Options::kDynamicBundle:
+                       break;
+       }
+       
+       // support re-export of individual symbols in MacOSX 10.7 and iOS 4.2
+       if ( (fOutputKind == kDynamicLibrary) && minOS(ld::mac10_7, ld::iPhone4_2) )
+               fCanReExportSymbols = true;
+       
+       // ObjC optimization is only in dynamic final linked images
+       switch ( fOutputKind ) {
+               case Options::kObjectFile:
+               case Options::kStaticExecutable:
+               case Options::kPreload:
+               case Options::kKextBundle:
+               case Options::kDyld:
+                       fObjcCategoryMerging = false;
+                       break;
+               case Options::kDynamicExecutable:
+               case Options::kDynamicLibrary:
+               case Options::kDynamicBundle:
+                       break;
+       }
+
+       // i386 main executables linked on Mac OS X 10.7 default to NX heap
+       // regardless of target unless overriden with -allow_heap_execute anywhere
+       // on the command line
+       if ( (fArchitecture == CPU_TYPE_I386) && (fOutputKind == kDynamicExecutable) && !fDisableNonExecutableHeap)
+               fNonExecutableHeap = true;
 }
 
 void Options::checkIllegalOptionCombinations()
@@ -3270,7 +3596,7 @@ void Options::checkIllegalOptionCombinations()
 
        // sync reader options
        if ( fNameSpace != kTwoLevelNameSpace )
-               fReaderOptions.fFlatNamespace = true;
+               fFlatNamespace = true;
 
        // check -stack_addr
        if ( fStackAddr != 0 ) {
@@ -3333,6 +3659,8 @@ void Options::checkIllegalOptionCombinations()
                        case Options::kKextBundle:
                                throw "-stack_size option can only be used when linking a main executable";
                }
+               if ( fStackSize > fStackAddr )
+                       throwf("-stack_size (0x%08llX) must be smaller than -stack_addr (0x%08llX)", fStackSize, fStackAddr);
        }
 
        // check that -allow_stack_execute is only used with main executables
@@ -3352,6 +3680,25 @@ void Options::checkIllegalOptionCombinations()
                }
        }
 
+       // check that -allow_heap_execute is only used with i386 main executables
+       if ( fDisableNonExecutableHeap ) {
+               if ( fArchitecture != CPU_TYPE_I386 )
+                       throw "-allow_heap_execute option can only be used when linking for i386";
+               switch ( fOutputKind ) {
+                       case Options::kDynamicExecutable:
+                               // -allow_heap_execute only legal when building main executable
+                               break;
+                       case Options::kStaticExecutable:
+                       case Options::kDynamicLibrary:
+                       case Options::kDynamicBundle:
+                       case Options::kObjectFile:
+                       case Options::kDyld:
+                       case Options::kPreload:
+                       case Options::kKextBundle:
+                               throw "-allow_heap_execute option can only be used when linking a main executable";
+               }
+       }
+
        // check -client_name is only used when making a bundle or main executable
        if ( fClientName != NULL ) {
                switch ( fOutputKind ) {
@@ -3381,63 +3728,85 @@ void Options::checkIllegalOptionCombinations()
                throw "-dtrace can only be used when creating final linked images";
 
        // check -d can only be used with -r
-       if ( fReaderOptions.fMakeTentativeDefinitionsReal && (fOutputKind != Options::kObjectFile) )
+       if ( fMakeTentativeDefinitionsReal && (fOutputKind != Options::kObjectFile) )
                throw "-d can only be used with -r";
 
        // check that -root_safe is not used with -r
-       if ( fReaderOptions.fRootSafe && (fOutputKind == Options::kObjectFile) )
+       if ( fRootSafe && (fOutputKind == Options::kObjectFile) )
                throw "-root_safe cannot be used with -r";
 
        // check that -setuid_safe is not used with -r
-       if ( fReaderOptions.fSetuidSafe && (fOutputKind == Options::kObjectFile) )
+       if ( fSetuidSafe && (fOutputKind == Options::kObjectFile) )
                throw "-setuid_safe cannot be used with -r";
 
+       // rdar://problem/4718189 map ObjC class names to new runtime names
+       bool alterObjC1ClassNamesToObjC2 = false;
+       switch (fArchitecture) {
+               case CPU_TYPE_I386:
+                       // i386 only uses new symbols when using objc2 ABI
+                       if ( fObjCABIVersion2Override )
+                               alterObjC1ClassNamesToObjC2 = true;
+                       break;
+               case CPU_TYPE_POWERPC64:
+               case CPU_TYPE_X86_64:
+               case CPU_TYPE_ARM:
+                       alterObjC1ClassNamesToObjC2 = true;
+                       break;
+       }
+
        // make sure all required exported symbols exist
        std::vector<const char*> impliedExports;
-       for (NameSet::iterator it=fExportSymbols.regularBegin(); it != fExportSymbols.regularEnd(); it++) {
+       for (NameSet::iterator it=fExportSymbols.regularBegin(); it != fExportSymbols.regularEnd(); ++it) {
                const char* name = *it;
-               // never export .eh symbols
                const int len = strlen(name);
-               if ( (strcmp(&name[len-3], ".eh") == 0) || (strncmp(name, ".objc_category_name_", 20) == 0) ) 
+               if ( (strcmp(&name[len-3], ".eh") == 0) || (strncmp(name, ".objc_category_name_", 20) == 0) ) {
+                       // never export .eh symbols
                        warning("ignoring %s in export list", name);
-               else
+               }
+               else if ( (fArchitecture == CPU_TYPE_I386) && !fObjCABIVersion2Override && (strncmp(name, "_OBJC_CLASS_$", 13) == 0) ) {
+                       warning("ignoring Objc2 Class symbol %s in i386 export list", name);
+                       fRemovedExports.insert(name);
+               }
+               else if ( alterObjC1ClassNamesToObjC2 && (strncmp(name, ".objc_class_name_", 17) == 0) ) {
+                       // linking ObjC2 ABI, but have ObjC1 ABI name in export list.  Change it to intended name
+                       fRemovedExports.insert(name);
+                       char* temp;
+                       asprintf(&temp, "_OBJC_CLASS_$_%s", &name[17]);
+                       impliedExports.push_back(temp);
+                       asprintf(&temp, "_OBJC_METACLASS_$_%s", &name[17]);
+                       impliedExports.push_back(temp);
+               }
+               else {
                        fInitialUndefines.push_back(name);
-               if ( strncmp(name, ".objc_class_name_", 17) == 0 ) {
-                       // rdar://problem/4718189 map ObjC class names to new runtime names
-                       switch (fArchitecture) {
-                               case CPU_TYPE_I386:
-                                       // i386 only uses new symbols when using objc2 ABI
-                                       if ( !fObjCABIVersion2POverride )
-                                               break;
-                                       // when using objc2 ABI to same as archs below
-                               case CPU_TYPE_POWERPC64:
-                               case CPU_TYPE_X86_64:
-                           case CPU_TYPE_ARM:
-                                       char* temp;
-                                       asprintf(&temp, "_OBJC_CLASS_$_%s", &name[17]);
-                                       impliedExports.push_back(temp);
-                                       asprintf(&temp, "_OBJC_METACLASS_$_%s", &name[17]);
-                                       impliedExports.push_back(temp);
-                                       break;
-                       }
                }
        }
-       for (std::vector<const char*>::iterator it=impliedExports.begin(); it != impliedExports.end(); it++) {
+       fExportSymbols.remove(fRemovedExports);
+       for (std::vector<const char*>::iterator it=impliedExports.begin(); it != impliedExports.end(); ++it) {
                const char* name = *it;
                fExportSymbols.insert(name);
                fInitialUndefines.push_back(name);
        }
 
+       // make sure all required re-exported symbols exist
+       for (NameSet::iterator it=fReExportSymbols.regularBegin(); it != fReExportSymbols.regularEnd(); ++it) {
+               fInitialUndefines.push_back(*it);
+       }
+       
        // make sure that -init symbol exist
        if ( fInitFunctionName != NULL )
                fInitialUndefines.push_back(fInitFunctionName);
 
+       // make sure every alias base exists
+       for (std::vector<AliasPair>::iterator it=fAliases.begin(); it != fAliases.end(); ++it) {
+               fInitialUndefines.push_back(it->realName);
+       }
+
        // check custom segments
        if ( fCustomSegmentAddresses.size() != 0 ) {
                // verify no segment is in zero page
                if ( fZeroPageSize != ULLONG_MAX ) {
                        for (std::vector<SegmentStart>::iterator it = fCustomSegmentAddresses.begin(); it != fCustomSegmentAddresses.end(); ++it) {
-                               if ( (it->address >= 0) && (it->address < fZeroPageSize) )
+                               if ( it->address < fZeroPageSize )
                                        throwf("-segaddr %s 0x%llX conflicts with -pagezero_size", it->name, it->address);
                        }
                }
@@ -3464,7 +3833,7 @@ void Options::checkIllegalOptionCombinations()
                                break;
                        case CPU_TYPE_POWERPC64:
                                // first 4GB for ppc64 on 10.5
-                               if ( fReaderOptions.fMacVersionMin >= ObjectFile::ReaderOptions::k10_5 )
+                               if ( fMacVersionMin >= ld::mac10_5 )
                                        fZeroPageSize = 0x100000000ULL;
                                else
                                        fZeroPageSize = 0x1000; // 10.4 dyld may not be able to handle >4GB zero page
@@ -3495,13 +3864,21 @@ void Options::checkIllegalOptionCombinations()
                }
        }
 
+       // if main executable with custom base address, model zero page as custom segment
+       if ( (fOutputKind == Options::kDynamicExecutable) && (fBaseAddress != 0) && (fZeroPageSize != 0) ) {
+               SegmentStart seg;
+               seg.name = "__PAGEZERO";
+               seg.address = 0;;
+               fCustomSegmentAddresses.push_back(seg);
+       }
+
        // -dead_strip and -r are incompatible
-       if ( (fDeadStrip != kDeadStripOff) && (fOutputKind == Options::kObjectFile) )
+       if ( fDeadStrip && (fOutputKind == Options::kObjectFile) )
                throw "-r and -dead_strip cannot be used together";
 
        // can't use -rpath unless targeting 10.5 or later
        if ( fRPaths.size() > 0 ) {
-               if ( !minOS(ObjectFile::ReaderOptions::k10_5, ObjectFile::ReaderOptions::k2_0) )
+               if ( !minOS(ld::mac10_5, ld::iPhone2_0) )
                        throw "-rpath can only be used when targeting Mac OS X 10.5 or later";
                switch ( fOutputKind ) {
                        case Options::kDynamicExecutable:
@@ -3521,15 +3898,19 @@ void Options::checkIllegalOptionCombinations()
        if ( fPositionIndependentExecutable ) {
                switch ( fOutputKind ) {
                        case Options::kDynamicExecutable:
-                               // -no_pie anywhere on command line disable PIE
-                               if ( fDisablePositionIndependentExecutable )
-                                       fPositionIndependentExecutable = false;
+                               if ( !minOS(ld::mac10_5, ld::iPhone4_2) ) {
+                                       if ( fIPhoneVersionMin == ld::iPhoneVersionUnset )
+                                               throw "-pie can only be used when targeting Mac OS X 10.5 or later";
+                                       else
+                                               throw "-pie can only be used when targeting iOS 4.2 or later";
+                               }
                                break;
                        case Options::kPreload:
                                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:
@@ -3537,8 +3918,6 @@ void Options::checkIllegalOptionCombinations()
                        case Options::kKextBundle:
                                throw "-pie can only be used when linking a main executable";
                }
-               if ( !minOS(ObjectFile::ReaderOptions::k10_5, ObjectFile::ReaderOptions::k2_0) )
-                       throw "-pie can only be used when targeting Mac OS X 10.5 or later";
        }
        
        // check -read_only_relocs is not used with x86_64
@@ -3563,6 +3942,18 @@ void Options::checkIllegalOptionCombinations()
                        warning("-force_cpusubtype_ALL will become unsupported for ARM architectures");
                }
        }
+       
+       // -reexported_symbols_list can only be used with -dynamiclib
+       if ( !fReExportSymbols.empty() ) {
+               if ( fOutputKind != Options::kDynamicLibrary )
+                       throw "-reexported_symbols_list can only used used when created dynamic libraries";
+               if ( !minOS(ld::mac10_7, ld::iPhone4_2) )
+                       throw "targeted OS version does not support -reexported_symbols_list";
+       }
+       
+       // -dyld_env can only be used with main executables
+       if ( (fOutputKind != Options::kDynamicExecutable) && (fDyldEnvironExtras.size() != 0) )
+               throw "-dyld_env can only used used when created main executables";
 }      
 
 
@@ -3578,9 +3969,20 @@ void Options::checkForClassic(int argc, const char* argv[])
        bool newLinker = false;
        
        // build command line buffer in case ld crashes
+       const char* srcRoot = getenv("SRCROOT");
+       if ( srcRoot != NULL ) {
+               strlcpy(crashreporterBuffer, "SRCROOT=", crashreporterBufferSize);
+               strlcat(crashreporterBuffer, srcRoot, crashreporterBufferSize);
+               strlcat(crashreporterBuffer, "\n", crashreporterBufferSize);
+       }
+#ifdef LD_VERS
+       strlcat(crashreporterBuffer, LD_VERS, crashreporterBufferSize);
+       strlcat(crashreporterBuffer, "\n", crashreporterBufferSize);
+#endif
+       strlcat(crashreporterBuffer, "ld ", crashreporterBufferSize);
        for(int i=1; i < argc; ++i) {
-               strlcat(crashreporterBuffer, argv[i], 1000);
-               strlcat(crashreporterBuffer, " ", 1000);
+               strlcat(crashreporterBuffer, argv[i], crashreporterBufferSize);
+               strlcat(crashreporterBuffer, " ", crashreporterBufferSize);
        }
 
        for(int i=0; i < argc; ++i) {
@@ -3618,23 +4020,22 @@ void Options::checkForClassic(int argc, const char* argv[])
                        }
                }
        }
-       
+
        // -dtrace only supported by new linker
        if( dtraceFound )
                return;
 
        if( archFound ) {
                switch ( fArchitecture ) {
-               case CPU_TYPE_POWERPC:
                case CPU_TYPE_I386:
-        case CPU_TYPE_ARM:
-//                     if ( staticFound && (rFound || !creatingMachKernel) ) {
+               case CPU_TYPE_POWERPC:
+               case CPU_TYPE_ARM:
                        if ( (staticFound || kextFound) && !newLinker ) {
                                // this environment variable will disable use of ld_classic for -static links
                                if ( getenv("LD_NO_CLASSIC_LINKER_STATIC") == NULL ) {
                                        // ld_classic does not support -iphoneos_version_min, so change
                                        for(int j=0; j < argc; ++j) {
-                                               if ( strcmp(argv[j], "-iphoneos_version_min") == 0) {
+                                               if ( (strcmp(argv[j], "-iphoneos_version_min") == 0) || (strcmp(argv[j], "-ios_version_min") == 0) ) {
                                                        argv[j] = "-macosx_version_min";
                                                        if ( j < argc-1 )
                                                                argv[j+1] = "10.5";
@@ -3650,6 +4051,11 @@ void Options::checkForClassic(int argc, const char* argv[])
                                                                argv[j] = "-static";
                                                }
                                        }
+                                       // ld classic does not understand -demangle 
+                                       for(int j=0; j < argc; ++j) {
+                                               if ( strcmp(argv[j], "-demangle") == 0) 
+                                                       argv[j] = "-noprebind";
+                                       }
                                        this->gotoClassicLinker(argc, argv);
                                }
                        }
@@ -3667,6 +4073,15 @@ void Options::checkForClassic(int argc, const char* argv[])
 void Options::gotoClassicLinker(int argc, const char* argv[])
 {
        argv[0] = "ld_classic";
+       // in -v mode, print command line passed to ld_classic
+       for(int i=0; i < argc; ++i) {
+               if ( strcmp(argv[i], "-v") == 0 ) {
+                       for(int j=0; j < argc; ++j)
+                               printf("%s ", argv[j]);
+                       printf("\n");
+                       break;
+               }
+       }
        char rawPath[PATH_MAX];
        char path[PATH_MAX];
        uint32_t bufSize = PATH_MAX;
index 4a06a5e0f975d279220889c3198a2665f7abb20e..7ce5766a20fe280e8038db2b60c15fdecb291321 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2005-2007 Apple  Inc. All rights reserved.
+ * Copyright (c) 2005-2010 Apple  Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -33,7 +33,7 @@
 #include <ext/hash_set>
 #include <ext/hash_map>
 
-#include "ObjectFile.h"
+#include "ld.hpp"
 
 extern void throwf (const char* format, ...) __attribute__ ((noreturn,format(printf, 1, 2)));
 extern void warning(const char* format, ...) __attribute__((format(printf, 1, 2)));
@@ -41,12 +41,14 @@ extern void warning(const char* format, ...) __attribute__((format(printf, 1, 2)
 class LibraryOptions
 {
 public:
-       LibraryOptions() : fWeakImport(false), fReExport(false), fBundleLoader(false), fLazyLoad(false), fForceLoad(false) {}
+       LibraryOptions() : fWeakImport(false), fReExport(false), fBundleLoader(false), 
+                                               fLazyLoad(false), fUpward(false), fForceLoad(false) {}
        // for dynamic libraries
        bool            fWeakImport;
        bool            fReExport;
        bool            fBundleLoader;
        bool            fLazyLoad;
+       bool            fUpward;
        // for static libraries
        bool            fForceLoad;
 };
@@ -76,9 +78,9 @@ public:
        enum WeakReferenceMismatchTreatment { kWeakReferenceMismatchError, kWeakReferenceMismatchWeak,
                                                                                  kWeakReferenceMismatchNonWeak };
        enum CommonsMode { kCommonsIgnoreDylibs, kCommonsOverriddenByDylibs, kCommonsConflictsDylibsError };
-       enum DeadStripMode { kDeadStripOff, kDeadStripOn, kDeadStripOnPlusUnusedInits };
        enum UUIDMode { kUUIDNone, kUUIDRandom, kUUIDContent };
        enum LocalSymbolHandling { kLocalSymbolsAll, kLocalSymbolsNone, kLocalSymbolsSelectiveInclude, kLocalSymbolsSelectiveExclude };
+       enum DebugInfoStripping { kDebugInfoNone, kDebugInfoMinimal, kDebugInfoFull };
 
        struct FileInfo {
                const char*                             path;
@@ -93,6 +95,8 @@ public:
                const char*                             path;
                const uint8_t*                  data;
                uint64_t                                dataLen;
+               typedef ExtraSection* iterator;
+               typedef const ExtraSection* const_iterator;
        };
 
        struct SectionAlignment {
@@ -105,6 +109,7 @@ public:
                const char*                             symbolName;
                const char*                             objectFileName;
        };
+       typedef const OrderedSymbol*    OrderedSymbolsIterator;
 
        struct SegmentStart {
                const char*                             name;
@@ -127,112 +132,164 @@ public:
                const char*                             useInstead;
        };
 
+       struct AliasPair {
+               const char*                     realName;
+               const char*                     alias;
+       };
+
+       typedef const char* const*      UndefinesIterator;
 
-       const ObjectFile::ReaderOptions&        readerOptions();
-       const char*                                                     getOutputFilePath();
-       std::vector<FileInfo>&                          getInputFiles();
+//     const ObjectFile::ReaderOptions&        readerOptions();
+       const char*                                                     outputFilePath() const { return fOutputFile; }
+       const std::vector<FileInfo>&            getInputFiles() const { return fInputFiles; }
 
-       cpu_type_t                                      architecture() { return fArchitecture; }
-       bool                                            preferSubArchitecture() { return fHasPreferredSubType; }
-       cpu_subtype_t                           subArchitecture() { return fSubArchitecture; }
-       bool                                            allowSubArchitectureMismatches() { return fAllowCpuSubtypeMismatches; }
-       OutputKind                                      outputKind();
-       bool                                            prebind();
-       bool                                            bindAtLoad();
-       bool                                            fullyLoadArchives();
-       NameSpace                                       nameSpace();
-       const char*                                     installPath();                  // only for kDynamicLibrary
-       uint32_t                                        currentVersion();               // only for kDynamicLibrary
-       uint32_t                                        compatibilityVersion(); // only for kDynamicLibrary
-       const char*                                     entryName();                    // only for kDynamicExecutable or kStaticExecutable
+       cpu_type_t                                      architecture() const { return fArchitecture; }
+       bool                                            preferSubArchitecture() const { return fHasPreferredSubType; }
+       cpu_subtype_t                           subArchitecture() const { return fSubArchitecture; }
+       bool                                            allowSubArchitectureMismatches() const { return fAllowCpuSubtypeMismatches; }
+       bool                                            forceCpuSubtypeAll() const { return fForceSubtypeAll; }
+       const char*                                     architectureName() const { return fArchitectureName; }
+       void                                            setArchitecture(cpu_type_t, cpu_subtype_t subtype);
+       OutputKind                                      outputKind() const { return fOutputKind; }
+       bool                                            prebind() const { return fPrebind; }
+       bool                                            bindAtLoad() const { return fBindAtLoad; }
+       NameSpace                                       nameSpace() const { return fNameSpace; }
+       const char*                                     installPath() const;                    // only for kDynamicLibrary
+       uint32_t                                        currentVersion() const { return fDylibCurrentVersion; }         // only for kDynamicLibrary
+       uint32_t                                        compatibilityVersion() const { return fDylibCompatVersion; }    // only for kDynamicLibrary
+       const char*                                     entryName() const { return fEntryName; }                // only for kDynamicExecutable or kStaticExecutable
        const char*                                     executablePath();
-       uint64_t                                        baseAddress();
-       bool                                            keepPrivateExterns();                   // only for kObjectFile
-       bool                                            needsModuleTable();                             // only for kDynamicLibrary
-       bool                                            interposable(const char* name);
-       bool                                            hasExportRestrictList();                // -exported_symbol or -unexported_symbol
-       bool                                            hasExportMaskList();                    // just -exported_symbol
-       bool                                            hasWildCardExportRestrictList();
-       bool                                            allGlobalsAreDeadStripRoots();
-       bool                                            shouldExport(const char*);
-       bool                                            ignoreOtherArchInputFiles();
-       bool                                            forceCpuSubtypeAll();
-       bool                                            traceDylibs();
-       bool                                            traceArchives();
-       DeadStripMode                           deadStrip();
-       UndefinedTreatment                      undefinedTreatment();
-       ObjectFile::ReaderOptions::MacVersionMin        macosxVersionMin() { return fReaderOptions.fMacVersionMin; }
-       ObjectFile::ReaderOptions::IPhoneVersionMin     iphoneOSVersionMin() { return fReaderOptions.fIPhoneVersionMin; }
-       bool                                            minOS(ObjectFile::ReaderOptions::MacVersionMin mac, ObjectFile::ReaderOptions::IPhoneVersionMin iPhoneOS);
+       uint64_t                                        baseAddress() const { return fBaseAddress; }
+       uint64_t                                        maxAddress() const { return fMaxAddress; }
+       bool                                            keepPrivateExterns() const { return fKeepPrivateExterns; }              // only for kObjectFile
+       bool                                            needsModuleTable() const { return fNeedsModuleTable; }                  // only for kDynamicLibrary
+       bool                                            interposable(const char* name) const;
+       bool                                            hasExportRestrictList() const { return (fExportMode != kExportDefault); }       // -exported_symbol or -unexported_symbol
+       bool                                            hasExportMaskList() const { return (fExportMode == kExportSome); }              // just -exported_symbol
+       bool                                            hasWildCardExportRestrictList() const;
+       bool                                            hasReExportList() const { return ! fReExportSymbols.empty(); }
+       bool                                            wasRemovedExport(const char* sym) const { return ( fRemovedExports.find(sym) != fRemovedExports.end() ); }
+       bool                                            allGlobalsAreDeadStripRoots() const;
+       bool                                            shouldExport(const char*) const;
+       bool                                            shouldReExport(const char*) const;
+       bool                                            ignoreOtherArchInputFiles() const { return fIgnoreOtherArchFiles; }
+       bool                                            traceDylibs() const     { return fTraceDylibs; }
+       bool                                            traceArchives() const { return fTraceArchives; }
+       bool                                            deadCodeStrip() const   { return fDeadStrip; }
+       UndefinedTreatment                      undefinedTreatment() const { return fUndefinedTreatment; }
+       ld::MacVersionMin                       macosxVersionMin() const { return fMacVersionMin; }
+       ld::IPhoneVersionMin            iphoneOSVersionMin() const { return fIPhoneVersionMin; }
+       bool                                            minOS(ld::MacVersionMin mac, ld::IPhoneVersionMin iPhoneOS);
        bool                                            messagesPrefixedWithArchitecture();
        Treatment                                       picTreatment();
-       WeakReferenceMismatchTreatment  weakReferenceMismatchTreatment();
-       const char*                                     umbrellaName();
-       std::vector<const char*>&       allowableClients();
-       const char*                                     clientName();
-       const char*                                     initFunctionName();                     // only for kDynamicLibrary
+       WeakReferenceMismatchTreatment  weakReferenceMismatchTreatment() const { return fWeakReferenceMismatchTreatment; }
+       const char*                                     umbrellaName() const { return fUmbrellaName; }
+       const std::vector<const char*>& allowableClients() const { return fAllowableClients; }
+       const char*                                     clientName() const { return fClientName; }
+       const char*                                     initFunctionName() const { return fInitFunctionName; }                  // only for kDynamicLibrary
        const char*                                     dotOutputFile();
-       uint64_t                                        zeroPageSize();
-       bool                                            hasCustomStack();
-       uint64_t                                        customStackSize();
-       uint64_t                                        customStackAddr();
-       bool                                            hasExecutableStack();
-       std::vector<const char*>&       initialUndefines();
-       bool                                            printWhyLive(const char* name);
-       uint32_t                                        minimumHeaderPad();
-       uint64_t                                        segmentAlignment() { return fSegmentAlignment; }
-       bool                                            maxMminimumHeaderPad() { return fMaxMinimumHeaderPad; }
-       std::vector<ExtraSection>&      extraSections();
-       std::vector<SectionAlignment>&  sectionAlignments();
-       CommonsMode                                     commonsMode();
-       bool                                            warnCommons();
+       uint64_t                                        pageZeroSize() const { return fZeroPageSize; }
+       bool                                            hasCustomStack() const { return (fStackSize != 0); }
+       uint64_t                                        customStackSize() const { return fStackSize; }
+       uint64_t                                        customStackAddr() const { return fStackAddr; }
+       bool                                            hasExecutableStack() const { return fExecutableStack; }
+       bool                                            hasNonExecutableHeap() const { return fNonExecutableHeap; }
+       UndefinesIterator                       initialUndefinesBegin() const { return &fInitialUndefines[0]; }
+       UndefinesIterator                       initialUndefinesEnd() const { return &fInitialUndefines[fInitialUndefines.size()]; }
+       bool                                            printWhyLive(const char* name) const;
+       uint32_t                                        minimumHeaderPad() const { return fMinimumHeaderPad; }
+       bool                                            maxMminimumHeaderPad() const { return fMaxMinimumHeaderPad; }
+       ExtraSection::const_iterator    extraSectionsBegin() const { return &fExtraSections[0]; }
+       ExtraSection::const_iterator    extraSectionsEnd() const { return &fExtraSections[fExtraSections.size()]; }
+       CommonsMode                                     commonsMode() const { return fCommonsMode; }
+       bool                                            warnCommons() const { return fWarnCommons; }
        bool                                            keepRelocations();
-       FileInfo                                        findFile(const char* path);
-       UUIDMode                                        getUUIDMode() { return fUUIDMode; }
+       FileInfo                                        findFile(const char* path) const;
+       UUIDMode                                        UUIDMode() const { return fUUIDMode; }
        bool                                            warnStabs();
        bool                                            pauseAtEnd() { return fPause; }
-       bool                                            printStatistics() { return fStatistics; }
-       bool                                            printArchPrefix() { return fMessagesPrefixedWithArchitecture; }
+       bool                                            printStatistics() const { return fStatistics; }
+       bool                                            printArchPrefix() const { return fMessagesPrefixedWithArchitecture; }
        void                                            gotoClassicLinker(int argc, const char* argv[]);
-       bool                                            sharedRegionEligible() { return fSharedRegionEligible; }
-       bool                                            printOrderFileStatistics() { return fPrintOrderFileStatistics; }
+       bool                                            sharedRegionEligible() const { return fSharedRegionEligible; }
+       bool                                            printOrderFileStatistics() const { return fPrintOrderFileStatistics; }
        const char*                                     dTraceScriptName() { return fDtraceScriptName; }
        bool                                            dTrace() { return (fDtraceScriptName != NULL); }
-       std::vector<OrderedSymbol>&     orderedSymbols() { return fOrderedSymbols; }
-       bool                                            splitSeg() { return fSplitSegs; }
+       unsigned long                           orderedSymbolsCount() const { return fOrderedSymbols.size(); }
+       OrderedSymbolsIterator          orderedSymbolsBegin() const { return &fOrderedSymbols[0]; }
+       OrderedSymbolsIterator          orderedSymbolsEnd() const { return &fOrderedSymbols[fOrderedSymbols.size()]; }
+       bool                                            splitSeg() const { return fSplitSegs; }
        uint64_t                                        baseWritableAddress() { return fBaseWritableAddress; }
-       std::vector<SegmentStart>&      customSegmentAddresses() { return fCustomSegmentAddresses; }
-       std::vector<SegmentSize>&       customSegmentSizes() { return fCustomSegmentSizes; }
-       std::vector<SegmentProtect>& customSegmentProtections() { return fCustomSegmentProtections; }
-       bool                                            saveTempFiles() { return fSaveTempFiles; }
-       const std::vector<const char*>&   rpaths() { return fRPaths; }
+       uint64_t                                        segmentAlignment() const { return fSegmentAlignment; }
+       uint64_t                                        segPageSize(const char* segName) const;
+       uint64_t                                        customSegmentAddress(const char* segName) const;
+       bool                                            hasCustomSegmentAddress(const char* segName) const;
+       bool                                            hasCustomSectionAlignment(const char* segName, const char* sectName) const;
+       uint8_t                                         customSectionAlignment(const char* segName, const char* sectName) const;
+       uint32_t                                        initialSegProtection(const char*) const; 
+       uint32_t                                        maxSegProtection(const char*) const; 
+       bool                                            saveTempFiles() const { return fSaveTempFiles; }
+       const std::vector<const char*>&   rpaths() const { return fRPaths; }
        bool                                            readOnlyx86Stubs() { return fReadOnlyx86Stubs; }
-       std::vector<DylibOverride>&     dylibOverrides() { return fDylibOverrides; }
-       const char*                                     generatedMapPath() { return fMapPath; }
-       bool                                            positionIndependentExecutable() { return fPositionIndependentExecutable; }
-       Options::FileInfo                       findFileUsingPaths(const char* path);
-       bool                                            deadStripDylibs() { return fDeadStripDylibs; }
-       bool                                            allowedUndefined(const char* name) { return ( fAllowedUndefined.find(name) != fAllowedUndefined.end() ); }
-       bool                                            someAllowedUndefines() { return (fAllowedUndefined.size() != 0); }
+       const std::vector<DylibOverride>&       dylibOverrides() const { return fDylibOverrides; }
+       const char*                                     generatedMapPath() const { return fMapPath; }
+       bool                                            positionIndependentExecutable() const { return fPositionIndependentExecutable; }
+       Options::FileInfo                       findFileUsingPaths(const char* path) const;
+       bool                                            deadStripDylibs() const { return fDeadStripDylibs; }
+       bool                                            allowedUndefined(const char* name) const { return ( fAllowedUndefined.find(name) != fAllowedUndefined.end() ); }
+       bool                                            someAllowedUndefines() const { return (fAllowedUndefined.size() != 0); }
        LocalSymbolHandling                     localSymbolHandling() { return fLocalSymbolHandling; }
-       bool                                            keepLocalSymbol(const char* symbolName);
-       bool                                            allowTextRelocs() { return fAllowTextRelocs; }
-       bool                                            warnAboutTextRelocs() { return fWarnTextRelocs; }
-       bool                                            usingLazyDylibLinking() { return fUsingLazyDylibLinking; }
-       bool                                            verbose() { return fVerbose; }
-       bool                                            makeEncryptable() { return fEncryptable; }
-       bool                                            needsUnwindInfoSection() { return fReaderOptions.fAddCompactUnwindEncoding; }
-       std::vector<const char*>&       llvmOptions() { return fLLVMOptions; }
-       bool                                            makeClassicDyldInfo() { return fMakeClassicDyldInfo; }
-       bool                                            makeCompressedDyldInfo() { return fMakeCompressedDyldInfo; }
+       bool                                            keepLocalSymbol(const char* symbolName) const;
+       bool                                            allowTextRelocs() const { return fAllowTextRelocs; }
+       bool                                            warnAboutTextRelocs() const { return fWarnTextRelocs; }
+       bool                                            usingLazyDylibLinking() const { return fUsingLazyDylibLinking; }
+       bool                                            verbose() const { return fVerbose; }
+       bool                                            makeEncryptable() const { return fEncryptable; }
+       bool                                            needsUnwindInfoSection() const { return fAddCompactUnwindEncoding; }
+       const std::vector<const char*>& llvmOptions() const{ return fLLVMOptions; }
+       const std::vector<const char*>& dyldEnvironExtras() const{ return fDyldEnvironExtras; }
+       bool                                            makeCompressedDyldInfo() const { return fMakeCompressedDyldInfo; }
        bool                                            hasExportedSymbolOrder();
-       bool                                            exportedSymbolOrder(const char* sym, unsigned int* order);
+       bool                                            exportedSymbolOrder(const char* sym, unsigned int* order) const;
        bool                                            orderData() { return fOrderData; }
-       bool                                            errorOnOtherArchFiles() { return fErrorOnOtherArchFiles; }
-       bool                                            markAutoDeadStripDylib() { return fMarkDeadStrippableDylib; }
-       bool                                            removeEHLabels() { return fReaderOptions.fNoEHLabels; }
-       bool                                            useSimplifiedDylibReExports() { return fUseSimplifiedDylibReExports; }
-       bool                                            objCABIVersion2POverride() { return fObjCABIVersion2POverride; }
+       bool                                            errorOnOtherArchFiles() const { return fErrorOnOtherArchFiles; }
+       bool                                            markAutoDeadStripDylib() const { return fMarkDeadStrippableDylib; }
+       bool                                            removeEHLabels() const { return fNoEHLabels; }
+       bool                                            useSimplifiedDylibReExports() const { return fUseSimplifiedDylibReExports; }
+       bool                                            objCABIVersion2POverride() const { return fObjCABIVersion2Override; }
+       bool                                            useUpwardDylibs() const { return fCanUseUpwardDylib; }
+       bool                                            fullyLoadArchives() const { return fFullyLoadArchives; }
+       bool                                            loadAllObjcObjectsFromArchives() const { return fLoadAllObjcObjectsFromArchives; }
+       bool                                            autoOrderInitializers() const { return fAutoOrderInitializers; }
+       bool                                            optimizeZeroFill() const { return fOptimizeZeroFill; }
+       bool                                            logAllFiles() const { return fLogAllFiles; }
+       DebugInfoStripping                      debugInfoStripping() const { return fDebugInfoStripping; }
+       bool                                            flatNamespace() const { return fFlatNamespace; }
+       bool                                            linkingMainExecutable() const { return fLinkingMainExecutable; }
+       bool                                            implicitlyLinkIndirectPublicDylibs() const { return fImplicitlyLinkPublicDylibs; }
+       bool                                            whyLoad() const { return fWhyLoad; }
+       const char*                                     traceOutputFile() const { return fTraceOutputFile; }
+       bool                                            outputSlidable() const { return fOutputSlidable; }
+       bool                                            haveCmdLineAliases() const { return (fAliases.size() != 0); }
+       const std::vector<AliasPair>& cmdLineAliases() const { return fAliases; }
+       bool                                            makeTentativeDefinitionsReal() const { return fMakeTentativeDefinitionsReal; }
+       const char*                                     dyldInstallPath() const { return fDyldInstallPath; }
+       bool                                            warnWeakExports() const { return fWarnWeakExports; }
+       bool                                            objcGcCompaction() const { return fObjcGcCompaction; }
+       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                                            canReExportSymbols() const { return fCanReExportSymbols; }
+       const char*                                     tempLtoObjectPath() const { return fTempLtoObjectPath; }
+       bool                                            objcCategoryMerging() const { return fObjcCategoryMerging; }
+       bool                                            hasWeakBitTweaks() const;
+       bool                                            forceWeak(const char* symbolName) const;
+       bool                                            forceNotWeak(const char* symbolName) const;
+       bool                                            forceWeakNonWildCard(const char* symbolName) const;
+       bool                                            forceNotWeakNonWildcard(const char* symbolName) const;
 
 private:
        class CStringEquals
@@ -249,14 +306,17 @@ private:
        class SetWithWildcards {
        public:
                void                                    insert(const char*);
-               bool                                    contains(const char*);
-               bool                                    hasWildCards()  { return !fWildCard.empty(); }
-               NameSet::iterator               regularBegin()  { return fRegular.begin(); }
-               NameSet::iterator               regularEnd()    { return fRegular.end(); }
+               bool                                    contains(const char*) const;
+               bool                                    containsNonWildcard(const char*) const;
+               bool                                    empty() const                   { return fRegular.empty() && fWildCard.empty(); }
+               bool                                    hasWildCards() const    { return !fWildCard.empty(); }
+               NameSet::iterator               regularBegin() const    { return fRegular.begin(); }
+               NameSet::iterator               regularEnd() const              { return fRegular.end(); }
+               void                                    remove(const NameSet&); 
        private:
                static bool                             hasWildCards(const char*);
-               bool                                    wildCardMatch(const char* pattern, const char* candidate);
-               bool                                    inCharRange(const char*& range, unsigned char c);
+               bool                                    wildCardMatch(const char* pattern, const char* candidate) const;
+               bool                                    inCharRange(const char*& range, unsigned char c) const;
 
                NameSet                                                 fRegular;
                std::vector<const char*>                fWildCard;
@@ -271,7 +331,7 @@ private:
        FileInfo                                        findFramework(const char* frameworkName);
        FileInfo                                        findFramework(const char* rootName, const char* suffix);
        bool                                            checkForFile(const char* format, const char* dir, const char* rootName,
-                                                                                        FileInfo& result);
+                                                                                        FileInfo& result) const;
        uint32_t                                        parseVersionNumber(const char*);
        void                                            parseSectionOrderFile(const char* segment, const char* section, const char* path);
        void                                            parseOrderFile(const char* path, bool cstring);
@@ -300,11 +360,13 @@ private:
        void                                            loadSymbolOrderFile(const char* fileOfExports, NameToOrder& orderMapping);
 
 
-       ObjectFile::ReaderOptions                       fReaderOptions;
+
+//     ObjectFile::ReaderOptions                       fReaderOptions;
        const char*                                                     fOutputFile;
        std::vector<Options::FileInfo>          fInputFiles;
        cpu_type_t                                                      fArchitecture;
        cpu_subtype_t                                           fSubArchitecture;
+       const char*                                                     fArchitectureName;
        OutputKind                                                      fOutputKind;
        bool                                                            fHasPreferredSubType;
        bool                                                            fPrebind;
@@ -315,7 +377,7 @@ private:
        bool                                                            fErrorOnOtherArchFiles;
        bool                                                            fForceSubtypeAll;
        InterposeMode                                           fInterposeMode;
-       DeadStripMode                                           fDeadStrip;
+       bool                                                            fDeadStrip;
        NameSpace                                                       fNameSpace;
        uint32_t                                                        fDylibCompatVersion;
        uint32_t                                                        fDylibCurrentVersion;
@@ -323,11 +385,16 @@ private:
        const char*                                                     fFinalName;
        const char*                                                     fEntryName;
        uint64_t                                                        fBaseAddress;
+       uint64_t                                                        fMaxAddress;
        uint64_t                                                        fBaseWritableAddress;
        bool                                                            fSplitSegs;
        SetWithWildcards                                        fExportSymbols;
        SetWithWildcards                                        fDontExportSymbols;
        SetWithWildcards                                        fInterposeList;
+       SetWithWildcards                                        fForceWeakSymbols;
+       SetWithWildcards                                        fForceNotWeakSymbols;
+       SetWithWildcards                                        fReExportSymbols;
+       NameSet                                                         fRemovedExports;
        NameToOrder                                                     fExportSymbolsOrder;
        ExportMode                                                      fExportMode;
        LibrarySearchMode                                       fLibrarySearchMode;
@@ -347,14 +414,18 @@ private:
        const char*                                                     fDtraceScriptName;
        const char*                                                     fSegAddrTablePath;
        const char*                                                     fMapPath;
+       const char*                                                     fDyldInstallPath;
+       const char*                                                     fTempLtoObjectPath;
        uint64_t                                                        fZeroPageSize;
        uint64_t                                                        fStackSize;
        uint64_t                                                        fStackAddr;
        bool                                                            fExecutableStack;
+       bool                                                            fNonExecutableHeap;
+       bool                                                            fDisableNonExecutableHeap;
        uint32_t                                                        fMinimumHeaderPad;
        uint64_t                                                        fSegmentAlignment;
        CommonsMode                                                     fCommonsMode;
-       UUIDMode                                                        fUUIDMode;
+       enum UUIDMode                                           fUUIDMode;
        SetWithWildcards                                        fLocalSymbolsIncluded;
        SetWithWildcards                                        fLocalSymbolsExcluded;
        LocalSymbolHandling                                     fLocalSymbolHandling;
@@ -370,6 +441,7 @@ private:
        bool                                                            fPrintOrderFileStatistics;
        bool                                                            fReadOnlyx86Stubs;
        bool                                                            fPositionIndependentExecutable;
+       bool                                                            fPIEOnCommandLine;
        bool                                                            fDisablePositionIndependentExecutable;
        bool                                                            fMaxMinimumHeaderPad;
        bool                                                            fDeadStripDylibs;
@@ -379,12 +451,52 @@ private:
        bool                                                            fEncryptable;
        bool                                                            fOrderData;
        bool                                                            fMarkDeadStrippableDylib;
-       bool                                                            fMakeClassicDyldInfo;
        bool                                                            fMakeCompressedDyldInfo;
+       bool                                                            fMakeCompressedDyldInfoForceOff;
        bool                                                            fNoEHLabels;
        bool                                                            fAllowCpuSubtypeMismatches;
        bool                                                            fUseSimplifiedDylibReExports;
-       bool                                                            fObjCABIVersion2POverride;
+       bool                                                            fObjCABIVersion2Override;
+       bool                                                            fObjCABIVersion1Override;
+       bool                                                            fCanUseUpwardDylib;
+       bool                                                            fFullyLoadArchives;
+       bool                                                            fLoadAllObjcObjectsFromArchives;
+       bool                                                            fFlatNamespace;
+       bool                                                            fLinkingMainExecutable;
+       bool                                                            fForFinalLinkedImage;
+       bool                                                            fForStatic;
+       bool                                                            fForDyld;
+       bool                                                            fMakeTentativeDefinitionsReal;
+       bool                                                            fWhyLoad;
+       bool                                                            fRootSafe;
+       bool                                                            fSetuidSafe;
+       bool                                                            fImplicitlyLinkPublicDylibs;
+       bool                                                            fAddCompactUnwindEncoding;
+       bool                                                            fWarnCompactUnwind;
+       bool                                                            fRemoveDwarfUnwindIfCompactExists;
+       bool                                                            fAutoOrderInitializers;
+       bool                                                            fOptimizeZeroFill;
+       bool                                                            fLogObjectFiles;
+       bool                                                            fLogAllFiles;
+       bool                                                            fTraceDylibs;
+       bool                                                            fTraceIndirectDylibs;
+       bool                                                            fTraceArchives;
+       bool                                                            fOutputSlidable;
+       bool                                                            fWarnWeakExports;
+       bool                                                            fObjcGcCompaction;
+       bool                                                            fObjCGc;
+       bool                                                            fObjCGcOnly;
+       bool                                                            fDemangle;
+       bool                                                            fTLVSupport;
+       bool                                                            fVersionLoadCommand;
+       bool                                                            fFunctionStartsLoadCommand;
+       bool                                                            fCanReExportSymbols;
+       bool                                                            fObjcCategoryMerging;
+       DebugInfoStripping                                      fDebugInfoStripping;
+       const char*                                                     fTraceOutputFile;
+       ld::MacVersionMin                                       fMacVersionMin;
+       ld::IPhoneVersionMin                            fIPhoneVersionMin;
+       std::vector<AliasPair>                          fAliases;
        std::vector<const char*>                        fInitialUndefines;
        NameSet                                                         fAllowedUndefined;
        NameSet                                                         fWhyLive;
@@ -399,6 +511,7 @@ private:
        std::vector<const char*>                        fLibrarySearchPaths;
        std::vector<const char*>                        fFrameworkSearchPaths;
        std::vector<const char*>                        fSDKPaths;
+       std::vector<const char*>                        fDyldEnvironExtras;
        bool                                                            fSaveTempFiles;
 };
 
diff --git a/src/ld/OutputFile.cpp b/src/ld/OutputFile.cpp
new file mode 100644 (file)
index 0000000..bb368c2
--- /dev/null
@@ -0,0 +1,3503 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
+ *
+ * Copyright (c) 2009-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/sysctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+#include <mach/mach_time.h>
+#include <mach/vm_statistics.h>
+#include <mach/mach_init.h>
+#include <mach/mach_host.h>
+#include <uuid/uuid.h>
+#include <dlfcn.h>
+#include <mach-o/dyld.h>
+#include <mach-o/fat.h>
+
+#include <string>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+#include <list>
+#include <algorithm>
+#include <ext/hash_map>
+#include <ext/hash_set>
+
+#include <CommonCrypto/CommonDigest.h>
+#include <AvailabilityMacros.h>
+
+#include "MachOTrie.hpp"
+
+#include "Options.h"
+
+#include "OutputFile.h"
+#include "Architectures.hpp"
+#include "HeaderAndLoadCommands.hpp"
+#include "LinkEdit.hpp"
+#include "LinkEditClassic.hpp"
+
+
+namespace ld {
+namespace tool {
+
+
+OutputFile::OutputFile(const Options& opts) 
+       :
+               hasWeakExternalSymbols(false), usesWeakExternalSymbols(false), overridesWeakExternalSymbols(false), 
+               _noReExportedDylibs(false), hasThreadLocalVariableDefinitions(false), pieDisabled(false), 
+               headerAndLoadCommandsSection(NULL),
+               rebaseSection(NULL), bindingSection(NULL), weakBindingSection(NULL), 
+               lazyBindingSection(NULL), exportSection(NULL), 
+               splitSegInfoSection(NULL), functionStartsSection(NULL), 
+               symbolTableSection(NULL), stringPoolSection(NULL), 
+               localRelocationsSection(NULL), externalRelocationsSection(NULL), 
+               sectionRelocationsSection(NULL), 
+               indirectSymbolTableSection(NULL), 
+               _options(opts),
+               _hasDyldInfo(opts.makeCompressedDyldInfo()),
+               _hasSymbolTable(true),
+               _hasSectionRelocations(opts.outputKind() == Options::kObjectFile),
+               _hasSplitSegInfo(opts.sharedRegionEligible()),
+               _hasFunctionStartsInfo(opts.addFunctionStarts()),
+               _hasDynamicSymbolTable(true),
+               _hasLocalRelocations(!opts.makeCompressedDyldInfo()),
+               _hasExternalRelocations(!opts.makeCompressedDyldInfo()),
+               _encryptedTEXTstartOffset(0),
+               _encryptedTEXTendOffset(0),
+               _localSymbolsStartIndex(0),
+               _localSymbolsCount(0),
+               _globalSymbolsStartIndex(0),
+               _globalSymbolsCount(0),
+               _importSymbolsStartIndex(0),
+               _importSymbolsCount(0),
+               _sectionsRelocationsAtom(NULL),
+               _localRelocsAtom(NULL),
+               _externalRelocsAtom(NULL),
+               _symbolTableAtom(NULL),
+               _indirectSymbolTableAtom(NULL),
+               _rebasingInfoAtom(NULL),
+               _bindingInfoAtom(NULL),
+               _lazyBindingInfoAtom(NULL),
+               _weakBindingInfoAtom(NULL),
+               _exportInfoAtom(NULL),
+               _splitSegInfoAtom(NULL),
+               _functionStartsAtom(NULL)
+{
+}
+
+void OutputFile::dumpAtomsBySection(ld::Internal& state, bool printAtoms)
+{
+       fprintf(stderr, "SORTED:\n");
+       for (std::vector<ld::Internal::FinalSection*>::iterator it = state.sections.begin(); it != state.sections.end(); ++it) {
+               fprintf(stderr, "final section %p %s/%s %s start addr=0x%08llX, size=0x%08llX, alignment=%02d, fileOffset=0x%08llX\n", 
+                               (*it), (*it)->segmentName(), (*it)->sectionName(), (*it)->isSectionHidden() ? "(hidden)" : "", 
+                               (*it)->address, (*it)->size, (*it)->alignment, (*it)->fileOffset);
+               if ( printAtoms ) {
+                       std::vector<const ld::Atom*>& atoms = (*it)->atoms;
+                       for (std::vector<const ld::Atom*>::iterator ait = atoms.begin(); ait != atoms.end(); ++ait) {
+                               fprintf(stderr, "   %p (0x%04llX) %s\n", *ait, (*ait)->size(), (*ait)->name());
+                       }
+               }
+       }
+       fprintf(stderr, "DYLIBS:\n");
+       for (std::vector<ld::dylib::File*>::iterator it=state.dylibs.begin(); it != state.dylibs.end(); ++it )
+               fprintf(stderr, "  %s\n", (*it)->installPath());
+}      
+
+void OutputFile::write(ld::Internal& state)
+{
+       this->buildDylibOrdinalMapping(state);
+       this->addLoadCommands(state);
+       this->addLinkEdit(state);
+       this->setSectionSizesAndAlignments(state);
+       this->setLoadCommandsPadding(state);
+       this->assignFileOffsets(state);
+       this->assignAtomAddresses(state);
+       this->synthesizeDebugNotes(state);
+       this->buildSymbolTable(state);
+       this->generateLinkEditInfo(state);
+       this->makeSplitSegInfo(state);
+       this->updateLINKEDITAddresses(state);
+       //this->dumpAtomsBySection(state, false);
+       this->writeOutputFile(state);
+       this->writeMapFile(state);
+}
+
+bool OutputFile::findSegment(ld::Internal& state, uint64_t addr, uint64_t* start, uint64_t* end, uint32_t* index)
+{
+       uint32_t segIndex = 0;
+       ld::Internal::FinalSection* segFirstSection = NULL;
+       ld::Internal::FinalSection* lastSection = NULL;
+       for (std::vector<ld::Internal::FinalSection*>::iterator it = state.sections.begin(); it != state.sections.end(); ++it) {
+               ld::Internal::FinalSection* sect = *it;
+               if ( (segFirstSection == NULL ) || strcmp(segFirstSection->segmentName(), sect->segmentName()) != 0 ) {
+                       if ( segFirstSection != NULL ) {
+                               //fprintf(stderr, "findSegment(0x%llX) seg changed to %s\n", addr, sect->segmentName());
+                               if ( (addr >= segFirstSection->address) && (addr < lastSection->address+lastSection->size) ) {
+                                       *start = segFirstSection->address;
+                                       *end = lastSection->address+lastSection->size;
+                                       *index = segIndex;
+                                       return true;
+                               }
+                               ++segIndex;
+                       }
+                       segFirstSection = sect;
+               }
+               lastSection = sect;
+       }
+       return false;
+}
+
+
+void OutputFile::assignAtomAddresses(ld::Internal& state)
+{
+       for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.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;
+                       switch ( sect-> type() ) {
+                               case ld::Section::typeImportProxies:
+                                       // want finalAddress() of all proxy atoms to be zero
+                                       (const_cast<ld::Atom*>(atom))->setSectionStartAddress(0);
+                                       break;
+                               case ld::Section::typeAbsoluteSymbols:
+                                       // want finalAddress() of all absolute atoms to be value of abs symbol
+                                       (const_cast<ld::Atom*>(atom))->setSectionStartAddress(0);
+                                       break;
+                               case ld::Section::typeLinkEdit:
+                                       // linkedit layout is assigned later
+                                       break;
+                               default:
+                                       (const_cast<ld::Atom*>(atom))->setSectionStartAddress(sect->address);
+                                       break;
+                       }
+               }
+       }
+}
+
+void OutputFile::updateLINKEDITAddresses(ld::Internal& state)
+{
+       if ( _options.makeCompressedDyldInfo() ) {
+               // build dylb rebasing info  
+               assert(_rebasingInfoAtom != NULL);
+               _rebasingInfoAtom->encode();
+               
+               // build dyld binding info  
+               assert(_bindingInfoAtom != NULL);
+               _bindingInfoAtom->encode();
+               
+               // build dyld lazy binding info  
+               assert(_lazyBindingInfoAtom != NULL);
+               _lazyBindingInfoAtom->encode();
+               
+               // build dyld weak binding info  
+               assert(_weakBindingInfoAtom != NULL);
+               _weakBindingInfoAtom->encode();
+               
+               // build dyld export info  
+               assert(_exportInfoAtom != NULL);
+               _exportInfoAtom->encode();
+       }
+       
+       if ( _options.sharedRegionEligible() ) {
+               // build split seg info  
+               assert(_splitSegInfoAtom != NULL);
+               _splitSegInfoAtom->encode();
+       }
+
+       if ( _options.addFunctionStarts() ) {
+               // build function starts info  
+               assert(_functionStartsAtom != NULL);
+               _functionStartsAtom->encode();
+       }
+
+       // build classic symbol table  
+       assert(_symbolTableAtom != NULL);
+       _symbolTableAtom->encode();
+       assert(_indirectSymbolTableAtom != NULL);
+       _indirectSymbolTableAtom->encode();
+
+       // add relocations to .o files
+       if ( _options.outputKind() == Options::kObjectFile ) {
+               assert(_sectionsRelocationsAtom != NULL);
+               _sectionsRelocationsAtom->encode();
+       }
+
+       if ( ! _options.makeCompressedDyldInfo() ) {
+               // build external relocations 
+               assert(_externalRelocsAtom != NULL);
+               _externalRelocsAtom->encode();
+               // build local relocations 
+               assert(_localRelocsAtom != NULL);
+               _localRelocsAtom->encode();
+       }
+
+       // update address and file offsets now that linkedit content has been generated
+       uint64_t curLinkEditAddress = 0;
+       uint64_t curLinkEditfileOffset = 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 ) 
+                       continue;
+               if ( curLinkEditAddress == 0 ) {
+                       curLinkEditAddress = sect->address;
+                       curLinkEditfileOffset = sect->fileOffset;
+               }
+               uint16_t maxAlignment = 0;
+               uint64_t offset = 0;
+               for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+                       const ld::Atom* atom = *ait;
+                       //fprintf(stderr, "setting linkedit atom offset for %s\n", atom->name());
+                       if ( atom->alignment().powerOf2 > maxAlignment )
+                               maxAlignment = atom->alignment().powerOf2;
+                       // calculate section offset for this atom
+                       uint64_t alignment = 1 << atom->alignment().powerOf2;
+                       uint64_t currentModulus = (offset % alignment);
+                       uint64_t requiredModulus = atom->alignment().modulus;
+                       if ( currentModulus != requiredModulus ) {
+                               if ( requiredModulus > currentModulus )
+                                       offset += requiredModulus-currentModulus;
+                               else
+                                       offset += requiredModulus+alignment-currentModulus;
+                       }
+                       (const_cast<ld::Atom*>(atom))->setSectionOffset(offset);
+                       (const_cast<ld::Atom*>(atom))->setSectionStartAddress(curLinkEditAddress);
+                       offset += atom->size();
+               }
+               sect->size = offset;
+               // section alignment is that of a contained atom with the greatest alignment
+               sect->alignment = maxAlignment;
+               sect->address = curLinkEditAddress;
+               sect->fileOffset = curLinkEditfileOffset;
+               curLinkEditAddress += sect->size;
+               curLinkEditfileOffset += sect->size;
+       }
+       
+       _fileSize = state.sections.back()->fileOffset + state.sections.back()->size;
+}
+
+void OutputFile::setSectionSizesAndAlignments(ld::Internal& state)
+{
+       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::typeAbsoluteSymbols ) {
+                       // absolute symbols need their finalAddress() to their value
+                       for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+                               const ld::Atom* atom = *ait;
+                               (const_cast<ld::Atom*>(atom))->setSectionOffset(atom->objectAddress());
+                       }
+               }
+               else {
+                       uint16_t maxAlignment = 0;
+                       uint64_t offset = 0;
+                       for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+                               const ld::Atom* atom = *ait;
+                               if ( atom->alignment().powerOf2 > maxAlignment )
+                                       maxAlignment = atom->alignment().powerOf2;
+                               // calculate section offset for this atom
+                               uint64_t alignment = 1 << atom->alignment().powerOf2;
+                               uint64_t currentModulus = (offset % alignment);
+                               uint64_t requiredModulus = atom->alignment().modulus;
+                               if ( currentModulus != requiredModulus ) {
+                                       if ( requiredModulus > currentModulus )
+                                               offset += requiredModulus-currentModulus;
+                                       else
+                                               offset += requiredModulus+alignment-currentModulus;
+                               }
+                               // LINKEDIT atoms are laid out later
+                               if ( sect->type() != ld::Section::typeLinkEdit ) {
+                                       (const_cast<ld::Atom*>(atom))->setSectionOffset(offset);
+                                       offset += atom->size();
+                               }
+                               if ( (atom->scope() == ld::Atom::scopeGlobal) 
+                                       && (atom->definition() == ld::Atom::definitionRegular) 
+                                       && (atom->combine() == ld::Atom::combineByName) 
+                                       && ((atom->symbolTableInclusion() == ld::Atom::symbolTableIn) 
+                                        || (atom->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip)) ) {
+                                               this->hasWeakExternalSymbols = true;
+                                               if ( _options.warnWeakExports() ) 
+                                                       warning("weak external symbol: %s", atom->name());
+                               }
+                       }
+                       sect->size = offset;
+                       // section alignment is that of a contained atom with the greatest alignment
+                       sect->alignment = maxAlignment;
+                       // unless -sectalign command line option overrides
+                       if  ( _options.hasCustomSectionAlignment(sect->segmentName(), sect->sectionName()) )
+                               sect->alignment = _options.customSectionAlignment(sect->segmentName(), sect->sectionName());
+                       // each atom in __eh_frame has zero alignment to assure they pack together,
+                       // but compilers usually make the CFIs pointer sized, so we want whole section
+                       // to start on pointer sized boundary.
+                       if ( sect->type() == ld::Section::typeCFI )
+                               sect->alignment = 3;
+                       if ( sect->type() == ld::Section::typeTLVDefs )
+                               this->hasThreadLocalVariableDefinitions = true;
+               }
+       }
+}
+
+void OutputFile::setLoadCommandsPadding(ld::Internal& state)
+{
+       // In other sections, any extra space is put and end of segment.
+       // In __TEXT segment, any extra space is put after load commands to allow post-processing of load commands
+       // Do a reverse layout of __TEXT segment to determine padding size and adjust section size
+       uint64_t paddingSize = 0;
+       switch ( _options.outputKind() ) {
+               case Options::kDyld:
+                       // dyld itself has special padding requirements.  We want the beginning __text section to start at a stable address
+                       assert(strcmp(state.sections[1]->sectionName(),"__text") == 0);
+                       state.sections[1]->alignment = 12; // page align __text
+                       break;
+               case Options::kObjectFile:
+                       // mach-o .o files need no padding between load commands and first section
+                       // but leave enough room that the object file could be signed
+                       paddingSize = 32;
+                       break;
+               case Options::kPreload:
+                       // mach-o MH_PRELOAD files need no padding between load commands and first section
+                       paddingSize = 0;
+               default:
+                       // work backwards from end of segment and lay out sections so that extra room goes to padding atom
+                       uint64_t addr = 0;
+                       for (std::vector<ld::Internal::FinalSection*>::reverse_iterator it = state.sections.rbegin(); it != state.sections.rend(); ++it) {
+                               ld::Internal::FinalSection* sect = *it;
+                               if ( strcmp(sect->segmentName(), "__TEXT") != 0 ) 
+                                       continue;
+                               if ( sect == headerAndLoadCommandsSection ) {
+                                       addr -= headerAndLoadCommandsSection->size;
+                                       paddingSize = addr % _options.segmentAlignment();
+                                       break;
+                               }
+                               addr -= sect->size;
+                               addr = addr & (0 - (1 << sect->alignment));
+                       }
+       
+                       // if command line requires more padding than this
+                       uint32_t minPad = _options.minimumHeaderPad();
+                       if ( _options.maxMminimumHeaderPad() ) {
+                               // -headerpad_max_install_names means there should be room for every path load command to grow to 1204 bytes
+                               uint32_t altMin = _dylibsToLoad.size() * MAXPATHLEN;
+                               if ( _options.outputKind() ==  Options::kDynamicLibrary )
+                                       altMin += MAXPATHLEN;
+                               if ( altMin > minPad )
+                                       minPad = altMin;
+                       }
+                       if ( paddingSize < minPad ) {
+                               int extraPages = (minPad - paddingSize + _options.segmentAlignment() - 1)/_options.segmentAlignment();
+                               paddingSize += extraPages * _options.segmentAlignment();
+                       }
+                       
+                       if ( _options.makeEncryptable() ) {
+                               // load commands must be on a separate non-encrypted page
+                               int loadCommandsPage = (headerAndLoadCommandsSection->size + minPad)/_options.segmentAlignment();
+                               int textPage = (headerAndLoadCommandsSection->size + paddingSize)/_options.segmentAlignment();
+                               if ( loadCommandsPage == textPage ) {
+                                       paddingSize += _options.segmentAlignment();
+                                       textPage += 1;
+                               }
+                               // remember start for later use by load command
+                               _encryptedTEXTstartOffset = textPage*_options.segmentAlignment();
+                       }
+                       break;
+       }
+       // add padding to size of section
+       headerAndLoadCommandsSection->size += paddingSize;
+}
+
+
+uint64_t OutputFile::pageAlign(uint64_t addr)
+{
+       const uint64_t alignment = _options.segmentAlignment();
+       return ((addr+alignment-1) & (-alignment)); 
+}
+
+uint64_t OutputFile::pageAlign(uint64_t addr, uint64_t pageSize)
+{
+       return ((addr+pageSize-1) & (-pageSize)); 
+}
+
+
+void OutputFile::assignFileOffsets(ld::Internal& state)
+{
+       const bool log = false;
+       const bool hiddenSectionsOccupyAddressSpace = ((_options.outputKind() != Options::kObjectFile)
+                                                                                               && (_options.outputKind() != Options::kPreload));
+       const bool segmentsArePageAligned = (_options.outputKind() != Options::kObjectFile);
+
+       uint64_t address = 0;
+       const char* lastSegName = "";
+       uint64_t floatingAddressStart = _options.baseAddress();
+       
+       // first pass, assign addresses to sections in segments with fixed start addresses
+       if ( log ) fprintf(stderr, "Fixed address segments:\n");
+       for (std::vector<ld::Internal::FinalSection*>::iterator it = state.sections.begin(); it != state.sections.end(); ++it) {
+               ld::Internal::FinalSection* sect = *it;
+               if ( ! _options.hasCustomSegmentAddress(sect->segmentName()) ) 
+                       continue;
+               if ( segmentsArePageAligned ) {
+                       if ( strcmp(lastSegName, sect->segmentName()) != 0 ) {
+                               address = _options.customSegmentAddress(sect->segmentName());
+                               lastSegName = sect->segmentName();
+                       }
+               }
+               // adjust section address based on alignment
+               uint64_t unalignedAddress = address;
+               uint64_t alignment = (1 << sect->alignment);
+               address = ( (unalignedAddress+alignment-1) & (-alignment) );
+       
+               // update section info
+               sect->address = address;
+               sect->alignmentPaddingBytes = (address - unalignedAddress);
+               
+               // sanity check size
+               if ( ((address + sect->size) > _options.maxAddress()) && (_options.outputKind() != Options::kObjectFile) 
+                                                                                                                         && (_options.outputKind() != Options::kStaticExecutable) )
+                       throwf("section %s (address=0x%08llX, size=%llu) would make the output executable exceed available address range", 
+                                               sect->sectionName(), address, sect->size);
+               
+               if ( log ) fprintf(stderr, "  address=0x%08llX, hidden=%d, alignment=%02d, section=%s,%s\n",
+                                               sect->address, sect->isSectionHidden(), sect->alignment, sect->segmentName(), sect->sectionName());
+               // update running totals
+               if ( !sect->isSectionHidden() || hiddenSectionsOccupyAddressSpace )
+                       address += sect->size;
+               
+               // if TEXT segment address is fixed, then flow other segments after it
+               if ( strcmp(sect->segmentName(), "__TEXT") == 0 ) {
+                       floatingAddressStart = address;
+               }
+       }
+       
+       // second pass, assign section address to sections in segments that are contiguous with previous segment
+       address = floatingAddressStart;
+       lastSegName = "";
+       if ( log ) fprintf(stderr, "Regular layout segments:\n");
+       for (std::vector<ld::Internal::FinalSection*>::iterator it = state.sections.begin(); it != state.sections.end(); ++it) {
+               ld::Internal::FinalSection* sect = *it;
+               if ( _options.hasCustomSegmentAddress(sect->segmentName()) ) 
+                       continue;
+               if ( (_options.outputKind() == Options::kPreload) && (sect->type() == ld::Section::typeMachHeader) ) {
+                       sect->alignmentPaddingBytes = 0;
+                       continue;
+               }
+               if ( segmentsArePageAligned ) {
+                       if ( strcmp(lastSegName, sect->segmentName()) != 0 ) {
+                               // round up size of last segment if needed
+                               if ( *lastSegName != '\0' ) {
+                                       address = pageAlign(address, _options.segPageSize(lastSegName));
+                               }
+                               // set segment address based on end of last segment
+                               address = pageAlign(address);
+                               lastSegName = sect->segmentName();
+                       }
+               }
+               // adjust section address based on alignment
+               uint64_t unalignedAddress = address;
+               uint64_t alignment = (1 << sect->alignment);
+               address = ( (unalignedAddress+alignment-1) & (-alignment) );
+       
+               // update section info
+               sect->address = address;
+               sect->alignmentPaddingBytes = (address - unalignedAddress);
+               
+               // sanity check size
+               if ( ((address + sect->size) > _options.maxAddress()) && (_options.outputKind() != Options::kObjectFile) 
+                                                                                                                         && (_options.outputKind() != Options::kStaticExecutable) )
+                               throwf("section %s (address=0x%08llX, size=%llu) would make the output executable exceed available address range", 
+                                               sect->sectionName(), address, sect->size);
+               
+               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, 
+                                                       sect->segmentName(), sect->sectionName());
+               // update running totals
+               if ( !sect->isSectionHidden() || hiddenSectionsOccupyAddressSpace )
+                       address += sect->size;
+       }
+       
+       
+       // third pass, assign section file offsets 
+       uint64_t fileOffset = 0;
+       lastSegName = "";
+       if ( log ) fprintf(stderr, "All segments with file offsets:\n");
+       for (std::vector<ld::Internal::FinalSection*>::iterator it = state.sections.begin(); it != state.sections.end(); ++it) {
+               ld::Internal::FinalSection* sect = *it;
+               if ( hasZeroForFileOffset(sect) ) {
+                       // fileoff of zerofill sections is moot, but historically it is set to zero
+                       sect->fileOffset = 0;
+               }
+               else {
+                       // page align file offset at start of each segment
+                       if ( segmentsArePageAligned && (*lastSegName != '\0') && (strcmp(lastSegName, sect->segmentName()) != 0) ) {
+                               fileOffset = pageAlign(fileOffset, _options.segPageSize(lastSegName));
+                       }
+                       lastSegName = sect->segmentName();
+
+                       // align file offset with address layout
+                       fileOffset += sect->alignmentPaddingBytes;
+                       
+                       // update section info
+                       sect->fileOffset = fileOffset;
+                       
+                       // update running total
+                       fileOffset += sect->size;
+               }
+               
+               if ( log ) fprintf(stderr, "  fileoffset=0x%08llX, address=0x%08llX, hidden=%d, size=%lld, alignment=%02d, section=%s,%s\n",
+                               sect->fileOffset, sect->address, sect->isSectionHidden(), sect->size, sect->alignment, 
+                               sect->segmentName(), sect->sectionName());
+       }
+
+
+       // for encrypted iPhoneOS apps
+       if ( _options.makeEncryptable() ) { 
+               // remember end of __TEXT for later use by load command
+               for (std::vector<ld::Internal::FinalSection*>::iterator it = state.sections.begin(); it != state.sections.end(); ++it) {
+                       ld::Internal::FinalSection* sect = *it;
+                       if ( strcmp(sect->segmentName(), "__TEXT") == 0 ) {
+                               _encryptedTEXTendOffset = pageAlign(sect->fileOffset);
+                       }
+               }
+       }
+
+       // remember total file size
+       _fileSize = fileOffset;
+}
+
+
+static const char* makeName(const ld::Atom& atom)
+{
+       static char buffer[4096];
+       switch ( atom.symbolTableInclusion() ) {
+               case ld::Atom::symbolTableNotIn:
+               case ld::Atom::symbolTableNotInFinalLinkedImages:
+                       sprintf(buffer, "%s@0x%08llX", atom.name(), atom.objectAddress());
+                       break;
+               case ld::Atom::symbolTableIn:
+               case ld::Atom::symbolTableInAndNeverStrip:
+               case ld::Atom::symbolTableInAsAbsolute:
+               case ld::Atom::symbolTableInWithRandomAutoStripLabel:
+                       strlcpy(buffer, atom.name(), 4096);
+                       break;
+       }
+       return buffer;
+}
+
+static const char* referenceTargetAtomName(ld::Internal& state, const ld::Fixup* ref)
+{
+       switch ( ref->binding ) {
+               case ld::Fixup::bindingNone:
+                       return "NO BINDING";
+               case ld::Fixup::bindingByNameUnbound:
+                       return (char*)(ref->u.target);
+               case ld::Fixup::bindingByContentBound:
+               case ld::Fixup::bindingDirectlyBound:
+                       return makeName(*((ld::Atom*)(ref->u.target)));
+               case ld::Fixup::bindingsIndirectlyBound:
+                       return makeName(*state.indirectBindingTable[ref->u.bindingIndex]);
+       }
+       return "BAD BINDING";
+}
+
+bool OutputFile::targetIsThumb(ld::Internal& state, const ld::Fixup* fixup)
+{
+       switch ( fixup->binding ) {
+               case ld::Fixup::bindingByContentBound:
+               case ld::Fixup::bindingDirectlyBound:
+                       return fixup->u.target->isThumb();
+               case ld::Fixup::bindingsIndirectlyBound:
+                       return state.indirectBindingTable[fixup->u.bindingIndex]->isThumb();
+               default:
+                       break;
+       }
+       throw "unexpected binding";
+}
+
+uint64_t OutputFile::addressOf(const ld::Internal& state, const ld::Fixup* fixup, const ld::Atom** target)
+{
+       if ( !_options.makeCompressedDyldInfo() ) {
+               // For external relocations the classic mach-o format
+               // has addend only stored in the content.  That means
+               // that the address of the target is not used.
+               if ( fixup->contentAddendOnly )
+                       return 0;
+       }
+       switch ( fixup->binding ) {
+               case ld::Fixup::bindingNone:
+                       throw "unexpected bindingNone";
+               case ld::Fixup::bindingByNameUnbound:
+                       throw "unexpected bindingByNameUnbound";
+               case ld::Fixup::bindingByContentBound:
+               case ld::Fixup::bindingDirectlyBound:
+                       *target = fixup->u.target;
+                       return (*target)->finalAddress();
+               case ld::Fixup::bindingsIndirectlyBound:
+                       *target = state.indirectBindingTable[fixup->u.bindingIndex];
+                       return (*target)->finalAddress();
+       }
+       throw "unexpected binding";
+}
+
+uint64_t OutputFile::sectionOffsetOf(const ld::Internal& state, const ld::Fixup* fixup)
+{
+       const ld::Atom* target = NULL;
+       switch ( fixup->binding ) {
+               case ld::Fixup::bindingNone:
+                       throw "unexpected bindingNone";
+               case ld::Fixup::bindingByNameUnbound:
+                       throw "unexpected bindingByNameUnbound";
+               case ld::Fixup::bindingByContentBound:
+               case ld::Fixup::bindingDirectlyBound:
+                       target = fixup->u.target;
+                       break;
+               case ld::Fixup::bindingsIndirectlyBound:
+                       target = state.indirectBindingTable[fixup->u.bindingIndex];
+                       break;
+       }
+       assert(target != NULL);
+       
+       uint64_t targetAddress = target->finalAddress();
+       for (std::vector<ld::Internal::FinalSection*>::const_iterator it = state.sections.begin(); it != state.sections.end(); ++it) {
+               const ld::Internal::FinalSection* sect = *it;
+               if ( (sect->address <= targetAddress) && (targetAddress < (sect->address+sect->size)) )
+                       return targetAddress - sect->address;
+       }
+       throw "section not found for section offset";
+}
+
+
+
+uint64_t OutputFile::tlvTemplateOffsetOf(const ld::Internal& state, const ld::Fixup* fixup)
+{
+       const ld::Atom* target = NULL;
+       switch ( fixup->binding ) {
+               case ld::Fixup::bindingNone:
+                       throw "unexpected bindingNone";
+               case ld::Fixup::bindingByNameUnbound:
+                       throw "unexpected bindingByNameUnbound";
+               case ld::Fixup::bindingByContentBound:
+               case ld::Fixup::bindingDirectlyBound:
+                       target = fixup->u.target;
+                       break;
+               case ld::Fixup::bindingsIndirectlyBound:
+                       target = state.indirectBindingTable[fixup->u.bindingIndex];
+                       break;
+       }
+       assert(target != NULL);
+       
+       for (std::vector<ld::Internal::FinalSection*>::const_iterator it = state.sections.begin(); it != state.sections.end(); ++it) {
+               const ld::Internal::FinalSection* sect = *it;
+               switch ( sect->type() ) {
+                       case ld::Section::typeTLVInitialValues:
+                       case ld::Section::typeTLVZeroFill:
+                               return target->finalAddress() - sect->address;
+                       default:
+                               break;
+               }
+       }
+       throw "section not found for tlvTemplateOffsetOf";
+}
+
+void OutputFile::printSectionLayout(ld::Internal& state)
+{
+       // show layout of final image
+       fprintf(stderr, "final section layout:\n");
+       for (std::vector<ld::Internal::FinalSection*>::iterator it = state.sections.begin(); it != state.sections.end(); ++it) {
+               if ( (*it)->isSectionHidden() )
+                       continue;
+               fprintf(stderr, "    %s/%s addr=0x%08llX, size=0x%08llX, fileOffset=0x%08llX, type=%d\n", 
+                               (*it)->segmentName(), (*it)->sectionName(), 
+                               (*it)->address, (*it)->size, (*it)->fileOffset, (*it)->type());
+       }
+}
+
+
+void OutputFile::rangeCheck8(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
+{
+       if ( (displacement > 127) || (displacement < -128) ) {
+               // show layout of final image
+               printSectionLayout(state);
+               
+               const ld::Atom* target; 
+               throwf("8-bit reference out of range (%lld max is +/-127B): from %s (0x%08llX) to %s (0x%08llX)", 
+                               displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup), 
+                               addressOf(state, fixup, &target));
+       }
+}
+
+void OutputFile::rangeCheck16(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
+{
+       const int64_t thirtyTwoKLimit  = 0x00007FFF;
+       if ( (displacement > thirtyTwoKLimit) || (displacement < (-thirtyTwoKLimit)) ) {
+               // show layout of final image
+               printSectionLayout(state);
+               
+               const ld::Atom* target; 
+               throwf("16-bit reference out of range (%lld max is +/-32KB): from %s (0x%08llX) to %s (0x%08llX)", 
+                               displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup),  
+                               addressOf(state, fixup, &target));
+       }
+}
+
+void OutputFile::rangeCheckBranch32(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
+{
+       const int64_t twoGigLimit  = 0x7FFFFFFF;
+       if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) {
+               // show layout of final image
+               printSectionLayout(state);
+               
+               const ld::Atom* target; 
+               throwf("32-bit branch out of range (%lld max is +/-4GB): from %s (0x%08llX) to %s (0x%08llX)", 
+                               displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup), 
+                               addressOf(state, fixup, &target));
+       }
+}
+
+void OutputFile::rangeCheckRIP32(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
+{
+       const int64_t twoGigLimit  = 0x7FFFFFFF;
+       if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) {
+               // show layout of final image
+               printSectionLayout(state);
+               
+               const ld::Atom* target; 
+               throwf("32-bit RIP relative reference out of range (%lld max is +/-4GB): from %s (0x%08llX) to %s (0x%08llX)", 
+                               displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup), 
+                               addressOf(state, fixup, &target));
+       }
+}
+
+void OutputFile::rangeCheckARM12(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
+{
+       if ( (displacement > 4092LL) || (displacement < (-4092LL)) ) {
+               // show layout of final image
+               printSectionLayout(state);
+               
+               const ld::Atom* target; 
+               throwf("ARM ldr 12-bit displacement out of range (%lld max is +/-4096B): from %s (0x%08llX) to %s (0x%08llX)", 
+                               displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup), 
+                               addressOf(state, fixup, &target));
+       }
+}
+
+
+void OutputFile::rangeCheckARMBranch24(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
+{
+       if ( (displacement > 33554428LL) || (displacement < (-33554432LL)) ) {
+               // show layout of final image
+               printSectionLayout(state);
+               
+               const ld::Atom* target; 
+               throwf("b/bl/blx ARM branch out of range (%lld max is +/-32MB): from %s (0x%08llX) to %s (0x%08llX)", 
+                               displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup), 
+                               addressOf(state, fixup, &target));
+       }
+}
+
+void OutputFile::rangeCheckThumbBranch22(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
+{
+       // armv7 supports a larger displacement
+       if ( _options.preferSubArchitecture() && (_options.subArchitecture() == CPU_SUBTYPE_ARM_V7) ) {
+               if ( (displacement > 16777214LL) || (displacement < (-16777216LL)) ) {
+                       // show layout of final image
+                       printSectionLayout(state);
+                       
+                       const ld::Atom* target; 
+                       throwf("b/bl/blx thumb2 branch out of range (%lld max is +/-16MB): from %s (0x%08llX) to %s (0x%08llX)", 
+                                       displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup), 
+                               addressOf(state, fixup, &target));
+               }
+       }
+       else {
+               if ( (displacement > 4194302LL) || (displacement < (-4194304LL)) ) {
+                       // show layout of final image
+                       printSectionLayout(state);
+                       
+                       const ld::Atom* target; 
+                       throwf("b/bl/blx thumb1 branch out of range (%lld max is +/-4MB): from %s (0x%08llX) to %s (0x%08llX)", 
+                                       displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup), 
+                               addressOf(state, fixup, &target));
+               }
+       }
+}
+
+void OutputFile::rangeCheckPPCBranch24(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
+{
+       const int64_t bl_eightMegLimit = 0x00FFFFFF;
+       if ( (displacement > bl_eightMegLimit) || (displacement < (-bl_eightMegLimit)) ) {
+               // show layout of final image
+               printSectionLayout(state);
+               
+               const ld::Atom* target; 
+               throwf("bl PPC branch out of range (%lld max is +/-16MB): from %s (0x%08llX) to %s (0x%08llX)", 
+                               displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup), 
+                               addressOf(state, fixup, &target));
+       }
+}
+
+void OutputFile::rangeCheckPPCBranch14(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
+{
+       const int64_t b_sixtyFourKiloLimit = 0x0000FFFF;
+       if ( (displacement > b_sixtyFourKiloLimit) || (displacement < (-b_sixtyFourKiloLimit)) ) {
+               // show layout of final image
+               printSectionLayout(state);
+               
+               const ld::Atom* target; 
+               throwf("bcc PPC branch out of range (%lld max is +/-64KB): from %s (0x%08llX) to %s (0x%08llX)", 
+                               displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup), 
+                               addressOf(state, fixup, &target));
+       }
+}
+
+
+
+
+uint16_t OutputFile::get16LE(uint8_t* loc) { return LittleEndian::get16(*(uint16_t*)loc); }
+void     OutputFile::set16LE(uint8_t* loc, uint16_t value) { LittleEndian::set16(*(uint16_t*)loc, value); }
+
+uint32_t OutputFile::get32LE(uint8_t* loc) { return LittleEndian::get32(*(uint32_t*)loc); }
+void     OutputFile::set32LE(uint8_t* loc, uint32_t value) { LittleEndian::set32(*(uint32_t*)loc, value); }
+
+uint64_t OutputFile::get64LE(uint8_t* loc) { return LittleEndian::get64(*(uint64_t*)loc); }
+void     OutputFile::set64LE(uint8_t* loc, uint64_t value) { LittleEndian::set64(*(uint64_t*)loc, value); }
+
+uint16_t OutputFile::get16BE(uint8_t* loc) { return BigEndian::get16(*(uint16_t*)loc); }
+void     OutputFile::set16BE(uint8_t* loc, uint16_t value) { BigEndian::set16(*(uint16_t*)loc, value); }
+
+uint32_t OutputFile::get32BE(uint8_t* loc) { return BigEndian::get32(*(uint32_t*)loc); }
+void     OutputFile::set32BE(uint8_t* loc, uint32_t value) { BigEndian::set32(*(uint32_t*)loc, value); }
+
+uint64_t OutputFile::get64BE(uint8_t* loc) { return BigEndian::get64(*(uint64_t*)loc); }
+void     OutputFile::set64BE(uint8_t* loc, uint64_t value) { BigEndian::set64(*(uint64_t*)loc, value); }
+
+void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::Atom* atom, uint8_t* buffer)
+{
+       //fprintf(stderr, "applyFixUps() on %s\n", atom->name());
+       int64_t accumulator = 0;
+       const ld::Atom* toTarget = NULL;        
+       const ld::Atom* fromTarget;
+       int64_t delta;
+       uint32_t instruction;
+       uint32_t newInstruction;
+       uint16_t instructionLowHalf;
+       bool is_bl;
+       bool is_blx;
+       bool is_b;
+       bool thumbTarget = false;
+       for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+               uint8_t* fixUpLocation = &buffer[fit->offsetInAtom];
+               switch ( (ld::Fixup::Kind)(fit->kind) ) { 
+                       case ld::Fixup::kindNone:
+                       case ld::Fixup::kindNoneFollowOn:
+                       case ld::Fixup::kindNoneGroupSubordinate:
+                       case ld::Fixup::kindNoneGroupSubordinateFDE:
+                       case ld::Fixup::kindNoneGroupSubordinateLSDA:
+                       case ld::Fixup::kindNoneGroupSubordinatePersonality:
+                               break;
+                       case ld::Fixup::kindSetTargetAddress:
+                               accumulator = addressOf(state, fit, &toTarget);                 
+                               thumbTarget = targetIsThumb(state, fit);
+                               if ( thumbTarget ) 
+                                       accumulator |= 1;
+                               if ( fit->contentAddendOnly || fit->contentDetlaToAddendOnly )
+                                       accumulator = 0;
+                               break;
+                       case ld::Fixup::kindSubtractTargetAddress:
+                               delta = addressOf(state, fit, &fromTarget);
+                               if ( ! fit->contentAddendOnly )
+                                       accumulator -= delta;
+                               break;
+                       case ld::Fixup::kindAddAddend:
+                               // <rdar://problem/8342028> ARM main executables main contain .long constants pointing
+                               // into themselves such as jump tables.  These .long should not have thumb bit set
+                               // even though the target is a thumb instruction. We can tell it is an interior pointer
+                               // because we are processing an addend. 
+                               if ( thumbTarget && (toTarget == atom) && ((int32_t)fit->u.addend > 0) ) {
+                                       accumulator &= (-2);
+                                       //warning("removing thumb bit from intra-atom pointer in %s %s+0x%0X", 
+                                       //              atom->section().sectionName(), atom->name(), fit->offsetInAtom);
+                               }
+                               accumulator += fit->u.addend;
+                               break;
+                       case ld::Fixup::kindSubtractAddend:
+                               accumulator -= fit->u.addend;
+                               break;
+                       case ld::Fixup::kindSetTargetImageOffset:
+                               accumulator = addressOf(state, fit, &toTarget) - mhAddress;
+                               break;
+                       case ld::Fixup::kindSetTargetSectionOffset:
+                               accumulator = sectionOffsetOf(state, fit);
+                               break;
+                       case ld::Fixup::kindSetTargetTLVTemplateOffset:
+                               accumulator = tlvTemplateOffsetOf(state, fit);
+                               break;
+                       case ld::Fixup::kindStore8:
+                               *fixUpLocation += accumulator;
+                               break;
+                       case ld::Fixup::kindStoreLittleEndian16:
+                               set16LE(fixUpLocation, accumulator);
+                               break;
+                       case ld::Fixup::kindStoreLittleEndianLow24of32:
+                               set32LE(fixUpLocation, (get32LE(fixUpLocation) & 0xFF000000) | (accumulator & 0x00FFFFFF) );
+                               break;
+                       case ld::Fixup::kindStoreLittleEndian32:
+                               set32LE(fixUpLocation, accumulator);
+                               break;
+                       case ld::Fixup::kindStoreLittleEndian64:
+                               set64LE(fixUpLocation, accumulator);
+                               break;
+                       case ld::Fixup::kindStoreBigEndian16:
+                               set16BE(fixUpLocation, accumulator);
+                               break;
+                       case ld::Fixup::kindStoreBigEndianLow24of32:
+                               set32BE(fixUpLocation, (get32BE(fixUpLocation) & 0xFF000000) | (accumulator & 0x00FFFFFF) );
+                               break;
+                       case ld::Fixup::kindStoreBigEndian32:
+                               set32BE(fixUpLocation, accumulator);
+                               break;
+                       case ld::Fixup::kindStoreBigEndian64:
+                               set64BE(fixUpLocation, accumulator);
+                               break;
+                       case ld::Fixup::kindStoreX86PCRel8:
+                       case ld::Fixup::kindStoreX86BranchPCRel8:
+                               if ( fit->contentAddendOnly )
+                                       delta = accumulator;
+                               else
+                                       delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 1);
+                               rangeCheck8(delta, state, atom, fit);
+                               *fixUpLocation = delta;
+                               break;
+                       case ld::Fixup::kindStoreX86PCRel16:
+                               if ( fit->contentAddendOnly )
+                                       delta = accumulator;
+                               else
+                                       delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 2);
+                               rangeCheck16(delta, state, atom, fit);
+                               set16LE(fixUpLocation, delta);
+                               break;
+                       case ld::Fixup::kindStoreX86BranchPCRel32:
+                               if ( fit->contentAddendOnly )
+                                       delta = accumulator;
+                               else
+                                       delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 4);
+                               rangeCheckBranch32(delta, state, atom, fit);
+                               set32LE(fixUpLocation, delta);
+                               break;
+                       case ld::Fixup::kindStoreX86PCRel32GOTLoad:
+                       case ld::Fixup::kindStoreX86PCRel32GOT:
+                       case ld::Fixup::kindStoreX86PCRel32:
+                       case ld::Fixup::kindStoreX86PCRel32TLVLoad:
+                               if ( fit->contentAddendOnly )
+                                       delta = accumulator;
+                               else
+                                       delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 4);
+                               rangeCheckRIP32(delta, state, atom, fit);
+                               set32LE(fixUpLocation, delta);
+                               break;
+                       case ld::Fixup::kindStoreX86PCRel32_1:
+                               if ( fit->contentAddendOnly )
+                                       delta = accumulator - 1;
+                               else
+                                       delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 5);
+                               rangeCheckRIP32(delta, state, atom, fit);
+                               set32LE(fixUpLocation, delta);
+                               break;
+                       case ld::Fixup::kindStoreX86PCRel32_2:
+                               if ( fit->contentAddendOnly )
+                                       delta = accumulator - 2;
+                               else
+                                       delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 6);
+                               rangeCheckRIP32(delta, state, atom, fit);
+                               set32LE(fixUpLocation, delta);
+                               break;
+                       case ld::Fixup::kindStoreX86PCRel32_4:
+                               if ( fit->contentAddendOnly )
+                                       delta = accumulator - 4;
+                               else
+                                       delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 8);
+                               rangeCheckRIP32(delta, state, atom, fit);
+                               set32LE(fixUpLocation, delta);
+                               break;
+                       case ld::Fixup::kindStoreX86Abs32TLVLoad:
+                               set32LE(fixUpLocation, accumulator);
+                               break;
+                       case ld::Fixup::kindStoreX86Abs32TLVLoadNowLEA:
+                               assert(_options.outputKind() != Options::kObjectFile);
+                               // TLV entry was optimized away, change movl instruction to a leal
+                               if ( fixUpLocation[-1] != 0xA1 )
+                                       throw "TLV load reloc does not point to a movl instruction";
+                               fixUpLocation[-1] = 0xB8;
+                               set32LE(fixUpLocation, accumulator);
+                               break;
+                       case ld::Fixup::kindStoreX86PCRel32GOTLoadNowLEA:
+                               assert(_options.outputKind() != Options::kObjectFile);
+                               // GOT entry was optimized away, change movq instruction to a leaq
+                               if ( fixUpLocation[-2] != 0x8B )
+                                       throw "GOT load reloc does not point to a movq instruction";
+                               fixUpLocation[-2] = 0x8D;
+                               delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 4);
+                               rangeCheckRIP32(delta, state, atom, fit);
+                               set32LE(fixUpLocation, delta);
+                               break;
+                       case ld::Fixup::kindStoreX86PCRel32TLVLoadNowLEA:
+                               assert(_options.outputKind() != Options::kObjectFile);
+                               // TLV entry was optimized away, change movq instruction to a leaq
+                               if ( fixUpLocation[-2] != 0x8B )
+                                       throw "TLV load reloc does not point to a movq instruction";
+                               fixUpLocation[-2] = 0x8D;
+                               delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 4);
+                               rangeCheckRIP32(delta, state, atom, fit);
+                               set32LE(fixUpLocation, delta);
+                               break;
+                       case ld::Fixup::kindStoreTargetAddressARMLoad12:
+                               accumulator = addressOf(state, fit, &toTarget);
+                               // fall into kindStoreARMLoad12 case
+                       case ld::Fixup::kindStoreARMLoad12:
+                               delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 8);
+                               rangeCheckARM12(delta, state, atom, fit);
+                               instruction = get32LE(fixUpLocation);
+                               if ( delta >= 0 ) {
+                                       newInstruction = instruction & 0xFFFFF000;
+                                       newInstruction |= ((uint32_t)delta & 0xFFF);
+                               }
+                               else {
+                                       newInstruction = instruction & 0xFF7FF000;
+                                       newInstruction |= ((uint32_t)(-delta) & 0xFFF);
+                               }
+                               set32LE(fixUpLocation, newInstruction);
+                               break;
+                       case ld::Fixup::kindStorePPCBranch14:
+                               delta = accumulator - (atom->finalAddress() + fit->offsetInAtom);
+                               rangeCheckPPCBranch14(delta, state, atom, fit);
+                               instruction = get32BE(fixUpLocation);
+                               newInstruction = (instruction & 0xFFFF0003) | ((uint32_t)delta & 0x0000FFFC);
+                               set32BE(fixUpLocation, newInstruction);
+                               break;
+                       case ld::Fixup::kindStorePPCPicLow14:
+                       case ld::Fixup::kindStorePPCAbsLow14:
+                               instruction = get32BE(fixUpLocation);
+                               if ( (accumulator & 0x3) != 0 )
+                                       throwf("bad offset (0x%08X) for lo14 instruction pic-base fix-up", (uint32_t)accumulator);
+                               newInstruction = (instruction & 0xFFFF0003) | (accumulator & 0xFFFC);
+                               set32BE(fixUpLocation, newInstruction);
+                               break;
+                       case ld::Fixup::kindStorePPCAbsLow16:
+                       case ld::Fixup::kindStorePPCPicLow16:
+                               instruction = get32BE(fixUpLocation);
+                               newInstruction = (instruction & 0xFFFF0000) | (accumulator & 0xFFFF);
+                               set32BE(fixUpLocation, newInstruction);
+                               break;
+                       case ld::Fixup::kindStorePPCAbsHigh16AddLow:
+                       case ld::Fixup::kindStorePPCPicHigh16AddLow:
+                               instructionLowHalf = (accumulator >> 16) & 0xFFFF;
+                               if ( accumulator & 0x00008000 )
+                                       ++instructionLowHalf;
+                               instruction = get32BE(fixUpLocation);
+                               newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
+                               set32BE(fixUpLocation, newInstruction);
+                               break;
+                       case ld::Fixup::kindStorePPCAbsHigh16:
+                               instruction = get32BE(fixUpLocation);
+                               newInstruction = (instruction & 0xFFFF0000) | ((accumulator >> 16) & 0xFFFF);
+                               set32BE(fixUpLocation, newInstruction);
+                               break;
+                       case ld::Fixup::kindDtraceExtra:
+                               break;
+                       case ld::Fixup::kindStoreX86DtraceCallSiteNop:
+                               if ( _options.outputKind() != Options::kObjectFile ) {
+                                       // change call site to a NOP
+                                       fixUpLocation[-1] = 0x90;       // 1-byte nop
+                                       fixUpLocation[0] = 0x0F;        // 4-byte nop 
+                                       fixUpLocation[1] = 0x1F;
+                                       fixUpLocation[2] = 0x40;
+                                       fixUpLocation[3] = 0x00;
+                               }
+                               break;
+                       case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
+                               if ( _options.outputKind() != Options::kObjectFile ) {
+                                       // change call site to a clear eax
+                                       fixUpLocation[-1] = 0x33;               // xorl eax,eax
+                                       fixUpLocation[0] = 0xC0;
+                                       fixUpLocation[1] = 0x90;                // 1-byte nop
+                                       fixUpLocation[2] = 0x90;                // 1-byte nop
+                                       fixUpLocation[3] = 0x90;                // 1-byte nop
+                               }
+                               break;
+                       case ld::Fixup::kindStorePPCDtraceCallSiteNop:
+                               if ( _options.outputKind() != Options::kObjectFile ) {
+                                       // change call site to a NOP
+                                       set32BE(fixUpLocation, 0x60000000);
+                               }
+                               break;
+                       case ld::Fixup::kindStorePPCDtraceIsEnableSiteClear:
+                               if ( _options.outputKind() != Options::kObjectFile ) {
+                                       // change call site to a li r3,0
+                                       set32BE(fixUpLocation, 0x38600000);
+                               }
+                               break;
+                       case ld::Fixup::kindStoreARMDtraceCallSiteNop:
+                               if ( _options.outputKind() != Options::kObjectFile ) {
+                                       // change call site to a NOP
+                                       set32LE(fixUpLocation, 0xE1A00000);
+                               }
+                               break;
+                       case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear:
+                               if ( _options.outputKind() != Options::kObjectFile ) {
+                                       // change call site to 'eor r0, r0, r0'
+                                       set32LE(fixUpLocation, 0xE0200000);
+                               }
+                               break;
+                       case ld::Fixup::kindStoreThumbDtraceCallSiteNop:
+                               if ( _options.outputKind() != Options::kObjectFile ) {
+                                       // change 32-bit blx call site to two thumb NOPs
+                                       set32LE(fixUpLocation, 0x46C046C0);
+                               }
+                               break;
+                       case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
+                               if ( _options.outputKind() != Options::kObjectFile ) {
+                                       // change 32-bit blx call site to 'nop', 'eor r0, r0'
+                                       set32LE(fixUpLocation, 0x46C04040);
+                               }
+                               break;
+                       case ld::Fixup::kindLazyTarget:
+                               break;
+                       case ld::Fixup::kindSetLazyOffset:
+                               assert(fit->binding == ld::Fixup::bindingDirectlyBound);
+                               accumulator = this->lazyBindingInfoOffsetForLazyPointerAddress(fit->u.target->finalAddress());
+                               break;
+                       case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+                               accumulator = addressOf(state, fit, &toTarget);
+                               thumbTarget = targetIsThumb(state, fit);
+                               if ( thumbTarget ) 
+                                       accumulator |= 1;
+                               if ( fit->contentAddendOnly )
+                                       accumulator = 0;
+                               set32LE(fixUpLocation, accumulator);
+                               break;
+                       case ld::Fixup::kindStoreTargetAddressLittleEndian64:
+                               accumulator = addressOf(state, fit, &toTarget);
+                               if ( fit->contentAddendOnly )
+                                       accumulator = 0;
+                               set64LE(fixUpLocation, accumulator);
+                               break;
+                       case ld::Fixup::kindStoreTargetAddressBigEndian32:
+                               accumulator = addressOf(state, fit, &toTarget);
+                               if ( fit->contentAddendOnly )
+                                       accumulator = 0;
+                               set32BE(fixUpLocation, accumulator);
+                               break;
+                       case ld::Fixup::kindStoreTargetAddressBigEndian64:
+                               accumulator = addressOf(state, fit, &toTarget);
+                               if ( fit->contentAddendOnly )
+                                       accumulator = 0;
+                               set64BE(fixUpLocation, accumulator);
+                               break;
+                       case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian32:
+                               accumulator = tlvTemplateOffsetOf(state, fit);
+                               set32LE(fixUpLocation, accumulator);
+                               break;
+                       case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian64:
+                               accumulator = tlvTemplateOffsetOf(state, fit);
+                               set64LE(fixUpLocation, accumulator);
+                               break;
+                       case ld::Fixup::kindStoreTargetAddressX86PCRel32:
+                       case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
+                       case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
+                       case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
+                               accumulator = addressOf(state, fit, &toTarget); 
+                               if ( fit->contentDetlaToAddendOnly )
+                                       accumulator = 0;
+                               if ( fit->contentAddendOnly )
+                                       delta = 0;
+                               else
+                                       delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 4);
+                               rangeCheckRIP32(delta, state, atom, fit);
+                               set32LE(fixUpLocation, delta);
+                               break;
+                       case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad:
+                               set32LE(fixUpLocation, accumulator);
+                               break;
+                       case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoadNowLEA:
+                               // TLV entry was optimized away, change movl instruction to a leal
+                               if ( fixUpLocation[-1] != 0xA1 )
+                                       throw "TLV load reloc does not point to a movl <abs-address>,<reg> instruction";
+                               fixUpLocation[-1] = 0xB8;
+                               accumulator = addressOf(state, fit, &toTarget);
+                               set32LE(fixUpLocation, accumulator);
+                               break;
+                       case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
+                               // GOT entry was optimized away, change movq instruction to a leaq
+                               if ( fixUpLocation[-2] != 0x8B )
+                                       throw "GOT load reloc does not point to a movq instruction";
+                               fixUpLocation[-2] = 0x8D;
+                               accumulator = addressOf(state, fit, &toTarget);
+                               delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 4);
+                               rangeCheckRIP32(delta, state, atom, fit);
+                               set32LE(fixUpLocation, delta);
+                               break;
+                       case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA:
+                               // TLV entry was optimized away, change movq instruction to a leaq
+                               if ( fixUpLocation[-2] != 0x8B )
+                                       throw "TLV load reloc does not point to a movq instruction";
+                               fixUpLocation[-2] = 0x8D;
+                               accumulator = addressOf(state, fit, &toTarget);
+                               delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 4);
+                               rangeCheckRIP32(delta, state, atom, fit);
+                               set32LE(fixUpLocation, delta);
+                               break;
+                       case ld::Fixup::kindStoreTargetAddressARMBranch24:
+                               accumulator = addressOf(state, fit, &toTarget);
+                               thumbTarget = targetIsThumb(state, fit);
+                               if ( thumbTarget ) 
+                                       accumulator |= 1;
+                               if ( fit->contentDetlaToAddendOnly )
+                                       accumulator = 0;
+                               // fall into kindStoreARMBranch24 case
+                       case ld::Fixup::kindStoreARMBranch24:
+                               // The pc added will be +8 from the pc
+                               delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 8);
+                               rangeCheckARMBranch24(delta, state, atom, fit);
+                               instruction = get32LE(fixUpLocation);
+                               // Make sure we are calling arm with bl, thumb with blx                 
+                               is_bl = ((instruction & 0xFF000000) == 0xEB000000);
+                               is_blx = ((instruction & 0xFE000000) == 0xFA000000);
+                               if ( is_bl && thumbTarget ) {
+                                       uint32_t opcode = 0xFA000000;
+                                       uint32_t disp = (uint32_t)(delta >> 2) & 0x00FFFFFF;
+                                       uint32_t h_bit = (uint32_t)(delta << 23) & 0x01000000;
+                                       newInstruction = opcode | h_bit | disp;
+                               } 
+                               else if ( is_blx && !thumbTarget ) {
+                                       uint32_t opcode = 0xEB000000;
+                                       uint32_t disp = (uint32_t)(delta >> 2) & 0x00FFFFFF;
+                                       newInstruction = opcode | disp;
+                               } 
+                               else if ( !is_bl && !is_blx && thumbTarget ) {
+                                       throwf("don't know how to convert instruction %x referencing %s to thumb",
+                                                instruction, referenceTargetAtomName(state, fit));
+                               }
+                               else {
+                                       newInstruction = (instruction & 0xFF000000) | ((uint32_t)(delta >> 2) & 0x00FFFFFF);
+                               }
+                               set32LE(fixUpLocation, newInstruction);
+                               break;
+                       case ld::Fixup::kindStoreTargetAddressThumbBranch22:
+                               accumulator = addressOf(state, fit, &toTarget);
+                               thumbTarget = targetIsThumb(state, fit);
+                               if ( thumbTarget ) 
+                                       accumulator |= 1;
+                               if ( fit->contentDetlaToAddendOnly )
+                                       accumulator = 0;
+                               // fall into kindStoreThumbBranch22 case
+                       case ld::Fixup::kindStoreThumbBranch22:
+                               instruction = get32LE(fixUpLocation);
+                               is_bl = ((instruction & 0xD000F800) == 0xD000F000);
+                               is_blx = ((instruction & 0xD000F800) == 0xC000F000);
+                               is_b = ((instruction & 0xD000F800) == 0x9000F000);
+                               // If the target is not thumb, we will be generating a blx instruction
+                               // Since blx cannot have the low bit set, set bit[1] of the target to
+                               // bit[1] of the base address, so that the difference is a multiple of
+                               // 4 bytes.
+                               if ( !thumbTarget ) {
+                                 accumulator &= -3ULL;
+                                 accumulator |= ((atom->finalAddress() + fit->offsetInAtom ) & 2LL);
+                               }
+                               // The pc added will be +4 from the pc
+                               delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 4);
+                               rangeCheckThumbBranch22(delta, state, atom, fit);
+                               if ( _options.preferSubArchitecture() && _options.subArchitecture() == CPU_SUBTYPE_ARM_V7 ) {
+                                       // The instruction is really two instructions:
+                                       // The lower 16 bits are the first instruction, which contains the high
+                                       //   11 bits of the displacement.
+                                       // The upper 16 bits are the second instruction, which contains the low
+                                       //   11 bits of the displacement, as well as differentiating bl and blx.
+                                       uint32_t s = (uint32_t)(delta >> 24) & 0x1;
+                                       uint32_t i1 = (uint32_t)(delta >> 23) & 0x1;
+                                       uint32_t i2 = (uint32_t)(delta >> 22) & 0x1;
+                                       uint32_t imm10 = (uint32_t)(delta >> 12) & 0x3FF;
+                                       uint32_t imm11 = (uint32_t)(delta >> 1) & 0x7FF;
+                                       uint32_t j1 = (i1 == s);
+                                       uint32_t j2 = (i2 == s);
+                                       if ( is_bl ) {
+                                               if ( thumbTarget )
+                                                       instruction = 0xD000F000; // keep bl
+                                               else
+                                                       instruction = 0xC000F000; // change to blx
+                                       } 
+                                       else if ( is_blx ) {
+                                               if ( thumbTarget )
+                                                       instruction = 0xD000F000; // change to bl
+                                               else
+                                                       instruction = 0xC000F000; // keep blx
+                                       }
+                                       else if ( is_b ) {
+                                               if ( !thumbTarget ) 
+                                                       throwf("don't know how to convert instruction %x referencing %s to arm",
+                                                                       instruction, referenceTargetAtomName(state, fit));
+                                               instruction = 0x9000F000; // keep b
+                                       } 
+                                       else if ( is_b ) {
+                                               if ( !thumbTarget ) 
+                                                       throwf("don't know how to convert branch instruction %x referencing %s to bx",
+                                                                       instruction, referenceTargetAtomName(state, fit));
+                                               instruction = 0x9000F000; // keep b
+                                       } 
+                                       uint32_t nextDisp = (j1 << 13) | (j2 << 11) | imm11;
+                                       uint32_t firstDisp = (s << 10) | imm10;
+                                       newInstruction = instruction | (nextDisp << 16) | firstDisp;
+                                       //warning("s=%d, j1=%d, j2=%d, imm10=0x%0X, imm11=0x%0X, opcode=0x%08X, first=0x%04X, next=0x%04X, new=0x%08X, disp=0x%llX for %s to %s\n",
+                                       //      s, j1, j2, imm10, imm11, opcode, firstDisp, nextDisp, newInstruction, delta, inAtom->getDisplayName(), ref->getTarget().getDisplayName());
+                                       set32LE(fixUpLocation, newInstruction);                         
+                               }
+                               else {
+                                       // The instruction is really two instructions:
+                                       // The lower 16 bits are the first instruction, which contains the high
+                                       //   11 bits of the displacement.
+                                       // The upper 16 bits are the second instruction, which contains the low
+                                       //   11 bits of the displacement, as well as differentiating bl and blx.
+                                       uint32_t firstDisp = (uint32_t)(delta >> 12) & 0x7FF;
+                                       uint32_t nextDisp = (uint32_t)(delta >> 1) & 0x7FF;
+                                       if ( is_bl && !thumbTarget ) {
+                                               instruction = 0xE800F000;
+                                       } 
+                                       else if ( is_blx && thumbTarget ) {
+                                               instruction = 0xF800F000;
+                                       } 
+                                       else if ( !is_bl && !is_blx && !thumbTarget ) {
+                                         throwf("don't know how to convert instruction %x referencing %s to arm",
+                                                        instruction, referenceTargetAtomName(state, fit));
+                                       } 
+                                       else {
+                                               instruction = instruction & 0xF800F800;
+                                       }
+                                       newInstruction = instruction | (nextDisp << 16) | firstDisp;
+                                       set32LE(fixUpLocation, newInstruction);                         
+                               }
+                               break;
+                       case ld::Fixup::kindStoreARMLow16:
+                               {
+                                       uint32_t imm4 = (accumulator & 0x0000F000) >> 12;
+                                       uint32_t imm12 = accumulator & 0x00000FFF;
+                                       instruction = get32LE(fixUpLocation);
+                                       newInstruction = (instruction & 0xFFF0F000) | (imm4 << 16) | imm12;
+                                       set32LE(fixUpLocation, newInstruction);         
+                               }
+                               break;
+                       case ld::Fixup::kindStoreARMHigh16:
+                               {
+                                       uint32_t imm4  = (accumulator & 0xF0000000) >> 28;
+                                       uint32_t imm12 = (accumulator & 0x0FFF0000) >> 16;
+                                       instruction = get32LE(fixUpLocation);
+                                       newInstruction = (instruction & 0xFFF0F000) | (imm4 << 16) | imm12;
+                                       set32LE(fixUpLocation, newInstruction);         
+                               }
+                               break;
+                       case ld::Fixup::kindStoreThumbLow16:
+                               {
+                                       uint32_t imm4 = (accumulator & 0x0000F000) >> 12;
+                                       uint32_t i =    (accumulator & 0x00000800) >> 11;
+                                       uint32_t imm3 = (accumulator & 0x00000700) >> 8;
+                                       uint32_t imm8 =  accumulator & 0x000000FF;
+                                       instruction = get32LE(fixUpLocation);
+                                       newInstruction = (instruction & 0x8F00FBF0) | imm4 | (i << 10) | (imm3 << 28) | (imm8 << 16);
+                                       set32LE(fixUpLocation, newInstruction);         
+                               }
+                               break;
+                       case ld::Fixup::kindStoreThumbHigh16:
+                               {
+                                       uint32_t imm4 = (accumulator & 0xF0000000) >> 28;
+                                       uint32_t i =    (accumulator & 0x08000000) >> 27;
+                                       uint32_t imm3 = (accumulator & 0x07000000) >> 24;
+                                       uint32_t imm8 = (accumulator & 0x00FF0000) >> 16;
+                                       instruction = get32LE(fixUpLocation);
+                                       newInstruction = (instruction & 0x8F00FBF0) | imm4 | (i << 10) | (imm3 << 28) | (imm8 << 16);
+                                       set32LE(fixUpLocation, newInstruction);         
+                               }
+                               break;
+                       case ld::Fixup::kindStoreTargetAddressPPCBranch24:
+                               accumulator = addressOf(state, fit, &toTarget);
+                               if ( fit->contentDetlaToAddendOnly )
+                                       accumulator = 0;
+                               // fall into kindStorePPCBranch24 case
+                       case ld::Fixup::kindStorePPCBranch24:
+                               delta = accumulator - (atom->finalAddress() + fit->offsetInAtom);
+                               rangeCheckPPCBranch24(delta, state, atom, fit);
+                               instruction = get32BE(fixUpLocation);
+                               newInstruction = (instruction & 0xFC000003) | ((uint32_t)delta & 0x03FFFFFC);
+                               set32BE(fixUpLocation, newInstruction);
+                               break;
+               }
+       }
+}
+
+void OutputFile::copyNoOps(uint8_t* from, uint8_t* to)
+{
+       switch ( _options.architecture() ) {
+               case CPU_TYPE_POWERPC:
+                       for (uint8_t* p=from; p < to; p += 4)
+                               OSWriteBigInt32((uint32_t*)p, 0, 0x60000000);
+                       break;
+               case CPU_TYPE_I386:
+               case CPU_TYPE_X86_64:
+                       for (uint8_t* p=from; p < to; ++p)
+                               *p = 0x90;
+                       break;
+               case CPU_TYPE_ARM:
+                       // fixme: need thumb nop?
+                       for (uint8_t* p=from; p < to; p += 4)
+                               OSWriteBigInt32((uint32_t*)p, 0, 0xe1a00000);
+                       break;
+               default:
+                       for (uint8_t* p=from; p < to; ++p)
+                               *p = 0x00;
+                       break;
+       }
+}
+
+bool OutputFile::takesNoDiskSpace(const ld::Section* sect)
+{
+       switch ( sect->type() ) {
+               case ld::Section::typeZeroFill:
+               case ld::Section::typeTLVZeroFill:
+                       return _options.optimizeZeroFill();
+               case ld::Section::typePageZero:
+               case ld::Section::typeStack:
+               case ld::Section::typeAbsoluteSymbols:
+               case ld::Section::typeTentativeDefs:
+                       return true;
+               default:
+                       break;
+       }
+       return false;
+}
+
+bool OutputFile::hasZeroForFileOffset(const ld::Section* sect)
+{
+       switch ( sect->type() ) {
+               case ld::Section::typeZeroFill:
+               case ld::Section::typeTLVZeroFill:
+                       return _options.optimizeZeroFill();
+               case ld::Section::typePageZero:
+               case ld::Section::typeStack:
+               case ld::Section::typeTentativeDefs:
+                       return true;
+               default:
+                       break;
+       }
+       return false;
+}
+
+
+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());
+
+       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;
+       bool lastAtomUsesNoOps = false;
+       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 ( takesNoDiskSpace(sect) )
+                       continue;
+               const bool sectionUsesNops = (sect->type() == ld::Section::typeCode);
+               //fprintf(stderr, "file offset=0x%08llX, section %s\n", sect->fileOffset, sect->sectionName());
+               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;
+                       if ( atom->definition() == ld::Atom::definitionProxy )
+                               continue;
+                       try {
+                               uint64_t fileOffset = atom->finalAddress() - sect->address + sect->fileOffset;
+                               // check for alignment padding between atoms
+                               if ( (fileOffset != fileOffsetOfEndOfLastAtom) && lastAtomUsesNoOps ) {
+                                       this->copyNoOps(&wholeBuffer[fileOffsetOfEndOfLastAtom], &wholeBuffer[fileOffset]);
+                               }
+                               // copy atom content
+                               atom->copyRawContent(&wholeBuffer[fileOffset]);
+                               // apply fix ups
+                               this->applyFixUps(state, mhAddress, atom, &wholeBuffer[fileOffset]);
+                               fileOffsetOfEndOfLastAtom = fileOffset+atom->size();
+                               lastAtomUsesNoOps = sectionUsesNops;
+                       }
+                       catch (const char* msg) {
+                               if ( atom->file() != NULL )
+                                       throwf("%s in %s from %s", msg, atom->name(), atom->file()->path());
+                               else
+                                       throwf("%s in %s", msg, atom->name());
+                       }
+               }
+       }
+       
+       // 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();
+               }
+       }
+
+       // 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);
+}
+
+struct AtomByNameSorter
+{      
+        bool operator()(const ld::Atom* left, const ld::Atom* right)
+        {
+          return (strcmp(left->name(), right->name()) < 0);
+        }
+};
+
+void OutputFile::buildSymbolTable(ld::Internal& state)
+{
+       unsigned int machoSectionIndex = 0;
+       for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+               ld::Internal::FinalSection* sect = *sit;
+               bool setMachoSectionIndex = !sect->isSectionHidden() && (sect->type() != ld::Section::typeTentativeDefs);
+               if ( setMachoSectionIndex ) 
+                       ++machoSectionIndex;
+               for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+                       const ld::Atom* atom = *ait;
+                       if ( setMachoSectionIndex ) 
+                               (const_cast<ld::Atom*>(atom))->setMachoSection(machoSectionIndex);
+                       else if ( sect->type() == ld::Section::typeMachHeader )
+                               (const_cast<ld::Atom*>(atom))->setMachoSection(1); // __mh_execute_header is not in any section by needs n_sect==1
+                       else if ( sect->type() == ld::Section::typeLastSection )
+                               (const_cast<ld::Atom*>(atom))->setMachoSection(machoSectionIndex); // use section index of previous section
+                       else if ( sect->type() == ld::Section::typeFirstSection )
+                               (const_cast<ld::Atom*>(atom))->setMachoSection(machoSectionIndex+1); // use section index of next section
+                               
+                       // in -r mode, clarify symbolTableNotInFinalLinkedImages
+                       if ( _options.outputKind() == Options::kObjectFile ) {
+                               if ( _options.architecture() == CPU_TYPE_X86_64 ) {
+                                       // x86_64 .o files need labels on anonymous literal strings
+                                       if ( (sect->type() == ld::Section::typeCString) && (atom->combine() == ld::Atom::combineByNameAndContent) ) {
+                                               (const_cast<ld::Atom*>(atom))->setSymbolTableInclusion(ld::Atom::symbolTableIn);
+                                               _localAtoms.push_back(atom);
+                                               continue;
+                                       }
+                               }
+                               if ( sect->type() == ld::Section::typeCFI ) {
+                                       if ( _options.removeEHLabels() )
+                                               (const_cast<ld::Atom*>(atom))->setSymbolTableInclusion(ld::Atom::symbolTableNotIn);
+                                       else
+                                               (const_cast<ld::Atom*>(atom))->setSymbolTableInclusion(ld::Atom::symbolTableIn);
+                               }
+                               if ( atom->symbolTableInclusion() == ld::Atom::symbolTableNotInFinalLinkedImages )
+                                       (const_cast<ld::Atom*>(atom))->setSymbolTableInclusion(ld::Atom::symbolTableIn);
+                       }
+
+                       // TEMP work around until <rdar://problem/7702923> goes in
+                       if ( (atom->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip)
+                               && (atom->scope() == ld::Atom::scopeLinkageUnit)
+                               && (_options.outputKind() == Options::kDynamicLibrary) ) {
+                                       (const_cast<ld::Atom*>(atom))->setScope(ld::Atom::scopeGlobal);
+                       }
+                       
+                       // <rdar://problem/6783167> support auto hidden weak symbols: .weak_def_can_be_hidden
+                       if ( atom->autoHide() && (_options.outputKind() != Options::kObjectFile) ) {
+                               // adding auto-hide symbol to .exp file should keep it global
+                               if ( !_options.hasExportMaskList() || !_options.shouldExport(atom->name()) )
+                                       (const_cast<ld::Atom*>(atom))->setScope(ld::Atom::scopeLinkageUnit);
+                       }
+                       
+                       // <rdar://problem/8626058> ld should consistently warn when resolvers are not exported
+                       if ( (atom->contentType() == ld::Atom::typeResolver) && (atom->scope() == ld::Atom::scopeLinkageUnit) )
+                               warning("resolver functions should be external, but '%s' is hidden", atom->name());
+                       
+                       if ( sect->type() == ld::Section::typeImportProxies ) {
+                               if ( atom->combine() == ld::Atom::combineByName )
+                                       this->usesWeakExternalSymbols = true;
+                               // alias proxy is a re-export with a name change, don't import changed name
+                               if ( ! atom->isAlias() )
+                                       _importedAtoms.push_back(atom);
+                               // scope of proxies are usually linkage unit, so done
+                               // if scope is global, we need to re-export it too
+                               if ( atom->scope() == ld::Atom::scopeGlobal )
+                                       _exportedAtoms.push_back(atom);
+                               continue;
+                       }
+                       if ( atom->symbolTableInclusion() == ld::Atom::symbolTableNotInFinalLinkedImages ) {
+                               assert(_options.outputKind() != Options::kObjectFile);
+                               continue;  // don't add to symbol table
+                       }
+                       if ( atom->symbolTableInclusion() == ld::Atom::symbolTableNotIn ) {
+                               continue;  // don't add to symbol table
+                       }
+                       
+                       if ( (atom->definition() == ld::Atom::definitionTentative) && (_options.outputKind() == Options::kObjectFile) ) {
+                               if ( _options.makeTentativeDefinitionsReal() ) {
+                                       // -r -d turns tentative defintions into real def
+                                       _exportedAtoms.push_back(atom);
+                               }
+                               else {
+                                       // in mach-o object files tentative defintions are stored like undefined symbols
+                                       _importedAtoms.push_back(atom);
+                               }
+                               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()) ) { 
+                                               _localAtoms.push_back(atom);
+                                       }
+                                       else {
+                                               if ( _options.outputKind() == Options::kObjectFile ) {
+                                                       (const_cast<ld::Atom*>(atom))->setSymbolTableInclusion(ld::Atom::symbolTableInWithRandomAutoStripLabel);
+                                                       _localAtoms.push_back(atom);
+                                               }
+                                               else
+                                                       (const_cast<ld::Atom*>(atom))->setSymbolTableInclusion(ld::Atom::symbolTableNotIn);
+                                       }       
+                                       break;
+                               case ld::Atom::scopeGlobal:
+                                       _exportedAtoms.push_back(atom);
+                                       break;
+                               case ld::Atom::scopeLinkageUnit:
+                                       if ( _options.outputKind() == Options::kObjectFile ) {
+                                               if ( _options.keepPrivateExterns() ) {
+                                                       assert( (atom->combine() == ld::Atom::combineNever) || (atom->combine() == ld::Atom::combineByName) );
+                                                       _exportedAtoms.push_back(atom);
+                                               }
+                                               else if ( _options.keepLocalSymbol(atom->name()) ) {
+                                                       _localAtoms.push_back(atom);
+                                               }
+                                               else {
+                                                       (const_cast<ld::Atom*>(atom))->setSymbolTableInclusion(ld::Atom::symbolTableInWithRandomAutoStripLabel);
+                                                       _localAtoms.push_back(atom);
+                                               }
+                                       }
+                                       else {
+                                               if ( _options.keepLocalSymbol(atom->name()) )
+                                                       _localAtoms.push_back(atom);
+                                               else
+                                                       (const_cast<ld::Atom*>(atom))->setSymbolTableInclusion(ld::Atom::symbolTableNotIn);
+                                       }
+                                       break;
+                       }
+               }
+       }
+       
+       // sort by name
+       std::sort(_exportedAtoms.begin(), _exportedAtoms.end(), AtomByNameSorter());
+       std::sort(_importedAtoms.begin(), _importedAtoms.end(), AtomByNameSorter());
+       
+}
+
+void OutputFile::addPreloadLinkEdit(ld::Internal& state)
+{
+       switch ( _options.architecture() ) {
+               case CPU_TYPE_I386:
+                       if ( _hasLocalRelocations ) {
+                               _localRelocsAtom = new LocalRelocationsAtom<x86>(_options, state, *this);
+                               localRelocationsSection = state.addAtom(*_localRelocsAtom);
+                       }
+                       if ( _hasExternalRelocations ) {
+                               _externalRelocsAtom = new ExternalRelocationsAtom<x86>(_options, state, *this);
+                               externalRelocationsSection = state.addAtom(*_externalRelocsAtom);
+                       }
+                       if ( _hasSymbolTable ) {
+                               _indirectSymbolTableAtom = new IndirectSymbolTableAtom<x86>(_options, state, *this);
+                               indirectSymbolTableSection = state.addAtom(*_indirectSymbolTableAtom);
+                               _symbolTableAtom = new SymbolTableAtom<x86>(_options, state, *this);
+                               symbolTableSection = state.addAtom(*_symbolTableAtom);
+                               _stringPoolAtom = new StringPoolAtom(_options, state, *this, 4);
+                               stringPoolSection = state.addAtom(*_stringPoolAtom);
+                       }
+                       break;
+               case CPU_TYPE_X86_64:
+                       if ( _hasLocalRelocations ) {
+                               _localRelocsAtom = new LocalRelocationsAtom<x86_64>(_options, state, *this);
+                               localRelocationsSection = state.addAtom(*_localRelocsAtom);
+                       }
+                       if ( _hasExternalRelocations ) {
+                               _externalRelocsAtom = new ExternalRelocationsAtom<x86_64>(_options, state, *this);
+                               externalRelocationsSection = state.addAtom(*_externalRelocsAtom);
+                       }
+                       if ( _hasSymbolTable ) {
+                               _indirectSymbolTableAtom = new IndirectSymbolTableAtom<x86_64>(_options, state, *this);
+                               indirectSymbolTableSection = state.addAtom(*_indirectSymbolTableAtom);
+                               _symbolTableAtom = new SymbolTableAtom<x86_64>(_options, state, *this);
+                               symbolTableSection = state.addAtom(*_symbolTableAtom);
+                               _stringPoolAtom = new StringPoolAtom(_options, state, *this, 4);
+                               stringPoolSection = state.addAtom(*_stringPoolAtom);
+                       }
+                       break;
+               case CPU_TYPE_ARM:
+                       if ( _hasLocalRelocations ) {
+                               _localRelocsAtom = new LocalRelocationsAtom<arm>(_options, state, *this);
+                               localRelocationsSection = state.addAtom(*_localRelocsAtom);
+                       }
+                       if ( _hasExternalRelocations ) {
+                               _externalRelocsAtom = new ExternalRelocationsAtom<arm>(_options, state, *this);
+                               externalRelocationsSection = state.addAtom(*_externalRelocsAtom);
+                       }
+                       if ( _hasSymbolTable ) {
+                               _indirectSymbolTableAtom = new IndirectSymbolTableAtom<arm>(_options, state, *this);
+                               indirectSymbolTableSection = state.addAtom(*_indirectSymbolTableAtom);
+                               _symbolTableAtom = new SymbolTableAtom<arm>(_options, state, *this);
+                               symbolTableSection = state.addAtom(*_symbolTableAtom);
+                               _stringPoolAtom = new StringPoolAtom(_options, state, *this, 4);
+                               stringPoolSection = state.addAtom(*_stringPoolAtom);
+                       }
+                       break;
+               default:
+                       throw "architecture not supported for -preload";
+       }
+
+}
+
+
+void OutputFile::addLinkEdit(ld::Internal& state)
+{
+       // for historical reasons, -preload orders LINKEDIT content differently
+       if  ( _options.outputKind() == Options::kPreload ) 
+               return addPreloadLinkEdit(state);
+       
+       switch ( _options.architecture() ) {
+               case CPU_TYPE_POWERPC:
+                       if ( _hasSectionRelocations ) {
+                               _sectionsRelocationsAtom = new SectionRelocationsAtom<ppc>(_options, state, *this);
+                               sectionRelocationsSection = state.addAtom(*_sectionsRelocationsAtom);
+                       }
+                       if ( _hasDyldInfo ) {
+                               _rebasingInfoAtom = new RebaseInfoAtom<ppc>(_options, state, *this);
+                               rebaseSection = state.addAtom(*_rebasingInfoAtom);
+                               
+                               _bindingInfoAtom = new BindingInfoAtom<ppc>(_options, state, *this);
+                               bindingSection = state.addAtom(*_bindingInfoAtom);
+                               
+                               _weakBindingInfoAtom = new WeakBindingInfoAtom<ppc>(_options, state, *this);
+                               weakBindingSection = state.addAtom(*_weakBindingInfoAtom);
+                               
+                               _lazyBindingInfoAtom = new LazyBindingInfoAtom<ppc>(_options, state, *this);
+                               lazyBindingSection = state.addAtom(*_lazyBindingInfoAtom);
+                               
+                               _exportInfoAtom = new ExportInfoAtom<ppc>(_options, state, *this);
+                               exportSection = state.addAtom(*_exportInfoAtom);
+                       }
+                       if ( _hasLocalRelocations ) {
+                               _localRelocsAtom = new LocalRelocationsAtom<ppc>(_options, state, *this);
+                               localRelocationsSection = state.addAtom(*_localRelocsAtom);
+                       }
+                       if ( _hasSplitSegInfo ) {
+                               _splitSegInfoAtom = new SplitSegInfoAtom<ppc>(_options, state, *this);
+                               splitSegInfoSection = state.addAtom(*_splitSegInfoAtom);
+                       }
+                       if ( _hasFunctionStartsInfo ) {
+                               _functionStartsAtom = new FunctionStartsAtom<ppc>(_options, state, *this);
+                               functionStartsSection = state.addAtom(*_functionStartsAtom);
+                       }
+                       if ( _hasSymbolTable ) {
+                               _symbolTableAtom = new SymbolTableAtom<ppc>(_options, state, *this);
+                               symbolTableSection = state.addAtom(*_symbolTableAtom);
+                       }
+                       if ( _hasExternalRelocations ) {
+                               _externalRelocsAtom = new ExternalRelocationsAtom<ppc>(_options, state, *this);
+                               externalRelocationsSection = state.addAtom(*_externalRelocsAtom);
+                       }
+                       if ( _hasSymbolTable ) {
+                               _indirectSymbolTableAtom = new IndirectSymbolTableAtom<ppc>(_options, state, *this);
+                               indirectSymbolTableSection = state.addAtom(*_indirectSymbolTableAtom);
+                               _stringPoolAtom = new StringPoolAtom(_options, state, *this, 4);
+                               stringPoolSection = state.addAtom(*_stringPoolAtom);
+                       }
+                       break;
+               case CPU_TYPE_I386:
+                       if ( _hasSectionRelocations ) {
+                               _sectionsRelocationsAtom = new SectionRelocationsAtom<x86>(_options, state, *this);
+                               sectionRelocationsSection = state.addAtom(*_sectionsRelocationsAtom);
+                       }
+                       if ( _hasDyldInfo ) {
+                               _rebasingInfoAtom = new RebaseInfoAtom<x86>(_options, state, *this);
+                               rebaseSection = state.addAtom(*_rebasingInfoAtom);
+                               
+                               _bindingInfoAtom = new BindingInfoAtom<x86>(_options, state, *this);
+                               bindingSection = state.addAtom(*_bindingInfoAtom);
+                               
+                               _weakBindingInfoAtom = new WeakBindingInfoAtom<x86>(_options, state, *this);
+                               weakBindingSection = state.addAtom(*_weakBindingInfoAtom);
+                               
+                               _lazyBindingInfoAtom = new LazyBindingInfoAtom<x86>(_options, state, *this);
+                               lazyBindingSection = state.addAtom(*_lazyBindingInfoAtom);
+                               
+                               _exportInfoAtom = new ExportInfoAtom<x86>(_options, state, *this);
+                               exportSection = state.addAtom(*_exportInfoAtom);
+                       }
+                       if ( _hasLocalRelocations ) {
+                               _localRelocsAtom = new LocalRelocationsAtom<x86>(_options, state, *this);
+                               localRelocationsSection = state.addAtom(*_localRelocsAtom);
+                       }
+                       if  ( _hasSplitSegInfo ) {
+                               _splitSegInfoAtom = new SplitSegInfoAtom<x86>(_options, state, *this);
+                               splitSegInfoSection = state.addAtom(*_splitSegInfoAtom);
+                       }
+                       if ( _hasFunctionStartsInfo ) {
+                               _functionStartsAtom = new FunctionStartsAtom<x86>(_options, state, *this);
+                               functionStartsSection = state.addAtom(*_functionStartsAtom);
+                       }
+                       if ( _hasSymbolTable ) {
+                               _symbolTableAtom = new SymbolTableAtom<x86>(_options, state, *this);
+                               symbolTableSection = state.addAtom(*_symbolTableAtom);
+                       }
+                       if ( _hasExternalRelocations ) {
+                               _externalRelocsAtom = new ExternalRelocationsAtom<x86>(_options, state, *this);
+                               externalRelocationsSection = state.addAtom(*_externalRelocsAtom);
+                       }
+                       if ( _hasSymbolTable ) {
+                               _indirectSymbolTableAtom = new IndirectSymbolTableAtom<x86>(_options, state, *this);
+                               indirectSymbolTableSection = state.addAtom(*_indirectSymbolTableAtom);
+                               _stringPoolAtom = new StringPoolAtom(_options, state, *this, 4);
+                               stringPoolSection = state.addAtom(*_stringPoolAtom);
+                       }
+                       break;
+               case CPU_TYPE_X86_64:
+                       if ( _hasSectionRelocations ) {
+                               _sectionsRelocationsAtom = new SectionRelocationsAtom<x86_64>(_options, state, *this);
+                               sectionRelocationsSection = state.addAtom(*_sectionsRelocationsAtom);
+                       }
+                       if ( _hasDyldInfo ) {
+                               _rebasingInfoAtom = new RebaseInfoAtom<x86_64>(_options, state, *this);
+                               rebaseSection = state.addAtom(*_rebasingInfoAtom);
+                               
+                               _bindingInfoAtom = new BindingInfoAtom<x86_64>(_options, state, *this);
+                               bindingSection = state.addAtom(*_bindingInfoAtom);
+                               
+                               _weakBindingInfoAtom = new WeakBindingInfoAtom<x86_64>(_options, state, *this);
+                               weakBindingSection = state.addAtom(*_weakBindingInfoAtom);
+                               
+                               _lazyBindingInfoAtom = new LazyBindingInfoAtom<x86_64>(_options, state, *this);
+                               lazyBindingSection = state.addAtom(*_lazyBindingInfoAtom);
+                               
+                               _exportInfoAtom = new ExportInfoAtom<x86_64>(_options, state, *this);
+                               exportSection = state.addAtom(*_exportInfoAtom);
+                       }
+                       if ( _hasLocalRelocations ) {
+                               _localRelocsAtom = new LocalRelocationsAtom<x86_64>(_options, state, *this);
+                               localRelocationsSection = state.addAtom(*_localRelocsAtom);
+                       }
+                       if  ( _hasSplitSegInfo ) {
+                               _splitSegInfoAtom = new SplitSegInfoAtom<x86_64>(_options, state, *this);
+                               splitSegInfoSection = state.addAtom(*_splitSegInfoAtom);
+                       }
+                       if ( _hasFunctionStartsInfo ) {
+                               _functionStartsAtom = new FunctionStartsAtom<x86_64>(_options, state, *this);
+                               functionStartsSection = state.addAtom(*_functionStartsAtom);
+                       }
+                       if ( _hasSymbolTable ) {
+                               _symbolTableAtom = new SymbolTableAtom<x86_64>(_options, state, *this);
+                               symbolTableSection = state.addAtom(*_symbolTableAtom);
+                       }
+                       if ( _hasExternalRelocations ) {
+                               _externalRelocsAtom = new ExternalRelocationsAtom<x86_64>(_options, state, *this);
+                               externalRelocationsSection = state.addAtom(*_externalRelocsAtom);
+                       }
+                       if ( _hasSymbolTable ) {
+                               _indirectSymbolTableAtom = new IndirectSymbolTableAtom<x86_64>(_options, state, *this);
+                               indirectSymbolTableSection = state.addAtom(*_indirectSymbolTableAtom);
+                               _stringPoolAtom = new StringPoolAtom(_options, state, *this, 8);
+                               stringPoolSection = state.addAtom(*_stringPoolAtom);
+                       }
+                       break;
+               case CPU_TYPE_ARM:
+                       if ( _hasSectionRelocations ) {
+                               _sectionsRelocationsAtom = new SectionRelocationsAtom<arm>(_options, state, *this);
+                               sectionRelocationsSection = state.addAtom(*_sectionsRelocationsAtom);
+                       }
+                       if ( _hasDyldInfo ) {
+                               _rebasingInfoAtom = new RebaseInfoAtom<arm>(_options, state, *this);
+                               rebaseSection = state.addAtom(*_rebasingInfoAtom);
+                               
+                               _bindingInfoAtom = new BindingInfoAtom<arm>(_options, state, *this);
+                               bindingSection = state.addAtom(*_bindingInfoAtom);
+                               
+                               _weakBindingInfoAtom = new WeakBindingInfoAtom<arm>(_options, state, *this);
+                               weakBindingSection = state.addAtom(*_weakBindingInfoAtom);
+                               
+                               _lazyBindingInfoAtom = new LazyBindingInfoAtom<arm>(_options, state, *this);
+                               lazyBindingSection = state.addAtom(*_lazyBindingInfoAtom);
+                               
+                               _exportInfoAtom = new ExportInfoAtom<arm>(_options, state, *this);
+                               exportSection = state.addAtom(*_exportInfoAtom);
+                       }
+                       if ( _hasLocalRelocations ) {
+                               _localRelocsAtom = new LocalRelocationsAtom<arm>(_options, state, *this);
+                               localRelocationsSection = state.addAtom(*_localRelocsAtom);
+                       }
+                       if  ( _hasSplitSegInfo ) {
+                               _splitSegInfoAtom = new SplitSegInfoAtom<arm>(_options, state, *this);
+                               splitSegInfoSection = state.addAtom(*_splitSegInfoAtom);
+                       }
+                       if ( _hasFunctionStartsInfo ) {
+                               _functionStartsAtom = new FunctionStartsAtom<arm>(_options, state, *this);
+                               functionStartsSection = state.addAtom(*_functionStartsAtom);
+                       }
+                       if ( _hasSymbolTable ) {
+                               _symbolTableAtom = new SymbolTableAtom<arm>(_options, state, *this);
+                               symbolTableSection = state.addAtom(*_symbolTableAtom);
+                       }
+                       if ( _hasExternalRelocations ) {
+                               _externalRelocsAtom = new ExternalRelocationsAtom<arm>(_options, state, *this);
+                               externalRelocationsSection = state.addAtom(*_externalRelocsAtom);
+                       }
+                       if ( _hasSymbolTable ) {
+                               _indirectSymbolTableAtom = new IndirectSymbolTableAtom<arm>(_options, state, *this);
+                               indirectSymbolTableSection = state.addAtom(*_indirectSymbolTableAtom);
+                               _stringPoolAtom = new StringPoolAtom(_options, state, *this, 4);
+                               stringPoolSection = state.addAtom(*_stringPoolAtom);
+                       }
+                       break;
+               case CPU_TYPE_POWERPC64:
+                       if ( _hasSectionRelocations ) {
+                               _sectionsRelocationsAtom = new SectionRelocationsAtom<ppc64>(_options, state, *this);
+                               sectionRelocationsSection = state.addAtom(*_sectionsRelocationsAtom);
+                       }
+                       if ( _hasDyldInfo ) {
+                               _rebasingInfoAtom = new RebaseInfoAtom<ppc64>(_options, state, *this);
+                               rebaseSection = state.addAtom(*_rebasingInfoAtom);
+                               
+                               _bindingInfoAtom = new BindingInfoAtom<ppc64>(_options, state, *this);
+                               bindingSection = state.addAtom(*_bindingInfoAtom);
+                               
+                               _weakBindingInfoAtom = new WeakBindingInfoAtom<ppc64>(_options, state, *this);
+                               weakBindingSection = state.addAtom(*_weakBindingInfoAtom);
+                               
+                               _lazyBindingInfoAtom = new LazyBindingInfoAtom<ppc64>(_options, state, *this);
+                               lazyBindingSection = state.addAtom(*_lazyBindingInfoAtom);
+                               
+                               _exportInfoAtom = new ExportInfoAtom<ppc64>(_options, state, *this);
+                               exportSection = state.addAtom(*_exportInfoAtom);
+                       }
+                       if ( _hasLocalRelocations ) {
+                               _localRelocsAtom = new LocalRelocationsAtom<ppc64>(_options, state, *this);
+                               localRelocationsSection = state.addAtom(*_localRelocsAtom);
+                       }
+                       if  ( _hasSplitSegInfo ) {
+                               _splitSegInfoAtom = new SplitSegInfoAtom<ppc64>(_options, state, *this);
+                               splitSegInfoSection = state.addAtom(*_splitSegInfoAtom);
+                       }
+                       if ( _hasFunctionStartsInfo ) {
+                               _functionStartsAtom = new FunctionStartsAtom<ppc64>(_options, state, *this);
+                               functionStartsSection = state.addAtom(*_functionStartsAtom);
+                       }
+                       if ( _hasSymbolTable ) {
+                               _symbolTableAtom = new SymbolTableAtom<ppc64>(_options, state, *this);
+                               symbolTableSection = state.addAtom(*_symbolTableAtom);
+                       }
+                       if ( _hasExternalRelocations ) {
+                               _externalRelocsAtom = new ExternalRelocationsAtom<ppc64>(_options, state, *this);
+                               externalRelocationsSection = state.addAtom(*_externalRelocsAtom);
+                       }
+                       if ( _hasSymbolTable ) {
+                               _indirectSymbolTableAtom = new IndirectSymbolTableAtom<ppc64>(_options, state, *this);
+                               indirectSymbolTableSection = state.addAtom(*_indirectSymbolTableAtom);
+                               _stringPoolAtom = new StringPoolAtom(_options, state, *this, 4);
+                               stringPoolSection = state.addAtom(*_stringPoolAtom);
+                       }
+                       break;
+               default:
+                       throw "unknown architecture";
+       }
+}
+
+void OutputFile::addLoadCommands(ld::Internal& state)
+{
+       switch ( _options.architecture() ) {
+               case CPU_TYPE_X86_64:
+                       _headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom<x86_64>(_options, state, *this);
+                       headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom);
+                       break;
+               case CPU_TYPE_ARM:
+                       _headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom<arm>(_options, state, *this);
+                       headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom);
+                       break;
+               case CPU_TYPE_I386:
+                       _headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom<x86>(_options, state, *this);
+                       headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom);
+                       break;
+               case CPU_TYPE_POWERPC:
+                       _headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom<ppc>(_options, state, *this);
+                       headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom);
+                       break;
+               case CPU_TYPE_POWERPC64:
+                       _headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom<ppc64>(_options, state, *this);
+                       headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom);
+                       break;
+               default:
+                       throw "unknown architecture";
+       }
+}
+
+uint32_t OutputFile::dylibCount()
+{
+       return _dylibsToLoad.size();
+}
+
+const ld::dylib::File* OutputFile::dylibByOrdinal(unsigned int ordinal)
+{
+       assert( ordinal > 0 );
+       assert( ordinal <= _dylibsToLoad.size() );
+       return _dylibsToLoad[ordinal-1];
+}
+
+bool OutputFile::hasOrdinalForInstallPath(const char* path, int* ordinal)
+{
+       for (std::map<const ld::dylib::File*, int>::const_iterator it = _dylibToOrdinal.begin(); it != _dylibToOrdinal.end(); ++it) {
+               const char* installPath = it->first->installPath();
+               if ( (installPath != NULL) && (strcmp(path, installPath) == 0) ) {
+                       *ordinal = it->second;
+                       return true;
+               }
+       }
+       return false;
+}
+
+uint32_t OutputFile::dylibToOrdinal(const ld::dylib::File* dylib)
+{
+       return _dylibToOrdinal[dylib];
+}
+
+
+void OutputFile::buildDylibOrdinalMapping(ld::Internal& state)
+{
+       // count non-public re-exported dylibs
+       unsigned int nonPublicReExportCount = 0;
+       for (std::vector<ld::dylib::File*>::iterator it = state.dylibs.begin(); it != state.dylibs.end(); ++it) {
+               ld::dylib::File* aDylib = *it;
+               if ( aDylib->willBeReExported() && ! aDylib->hasPublicInstallName() ) 
+                       ++nonPublicReExportCount;
+       }
+       
+       // look at each dylib supplied in state
+       bool hasReExports = false;
+       bool haveLazyDylibs = false;
+       for (std::vector<ld::dylib::File*>::iterator it = state.dylibs.begin(); it != state.dylibs.end(); ++it) {
+               ld::dylib::File* aDylib = *it;
+               int ordinal;
+               if ( aDylib == state.bundleLoader ) {
+                       _dylibToOrdinal[aDylib] = BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE;
+               }
+               else if ( this->hasOrdinalForInstallPath(aDylib->installPath(), &ordinal) ) {
+                       // already have a dylib with that install path, map all uses to that ordinal
+                       _dylibToOrdinal[aDylib] = ordinal;
+               }
+               else if ( aDylib->willBeLazyLoadedDylib() ) {
+                       // all lazy dylib need to be at end of ordinals
+                       haveLazyDylibs = true;
+               }
+               else if ( aDylib->willBeReExported() && ! aDylib->hasPublicInstallName() && (nonPublicReExportCount >= 2) ) {
+                       _dylibsToLoad.push_back(aDylib);
+                       _dylibToOrdinal[aDylib] = BIND_SPECIAL_DYLIB_SELF;
+               }
+               else {
+                       // first time this install path seen, create new ordinal
+                       _dylibsToLoad.push_back(aDylib);
+                       _dylibToOrdinal[aDylib] = _dylibsToLoad.size();
+               }
+               if ( aDylib->explicitlyLinked() && aDylib->willBeReExported() )
+                       hasReExports = true;
+       }
+       if ( haveLazyDylibs ) {
+               // second pass to determine ordinals for lazy loaded dylibs
+               for (std::vector<ld::dylib::File*>::iterator it = state.dylibs.begin(); it != state.dylibs.end(); ++it) {
+                       ld::dylib::File* aDylib = *it;
+                       if ( aDylib->willBeLazyLoadedDylib() ) {
+                               int ordinal;
+                               if ( this->hasOrdinalForInstallPath(aDylib->installPath(), &ordinal) ) {
+                                       // already have a dylib with that install path, map all uses to that ordinal
+                                       _dylibToOrdinal[aDylib] = ordinal;
+                               }
+                               else {
+                                       // first time this install path seen, create new ordinal
+                                       _dylibsToLoad.push_back(aDylib);
+                                       _dylibToOrdinal[aDylib] = _dylibsToLoad.size();
+                               }
+                       }
+               }
+       }
+       _noReExportedDylibs = !hasReExports;
+       //fprintf(stderr, "dylibs:\n");
+       //for (std::map<const ld::dylib::File*, int>::const_iterator it = _dylibToOrdinal.begin(); it != _dylibToOrdinal.end(); ++it) {
+       //      fprintf(stderr, " %p ord=%u, install_name=%s\n",it->first, it->second, it->first->installPath());
+       //}
+}
+
+uint32_t OutputFile::lazyBindingInfoOffsetForLazyPointerAddress(uint64_t lpAddress)
+{
+       return _lazyPointerAddressToInfoOffset[lpAddress];
+}
+
+void OutputFile::setLazyBindingInfoOffset(uint64_t lpAddress, uint32_t lpInfoOffset)
+{
+       _lazyPointerAddressToInfoOffset[lpAddress] = lpInfoOffset;
+}
+
+int OutputFile::compressedOrdinalForAtom(const ld::Atom* target)
+{
+       // flat namespace images use zero for all ordinals
+       if ( _options.nameSpace() != Options::kTwoLevelNameSpace )
+               return BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
+
+       // handle -interposable
+       if ( target->definition() == ld::Atom::definitionRegular )
+               return BIND_SPECIAL_DYLIB_SELF;
+
+       // regular ordinal
+       const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(target->file());
+       if ( dylib != NULL )
+               return _dylibToOrdinal[dylib]; 
+
+       // handle undefined dynamic_lookup
+       if ( _options.undefinedTreatment() == Options::kUndefinedDynamicLookup )
+               return BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
+       
+       // handle -U _foo
+       if ( _options.allowedUndefined(target->name()) )
+               return BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
+
+       throw "can't find ordinal for imported symbol";
+}
+
+
+bool OutputFile::isPcRelStore(ld::Fixup::Kind kind)
+{
+       switch ( kind ) { 
+               case ld::Fixup::kindStoreX86BranchPCRel8:
+               case ld::Fixup::kindStoreX86BranchPCRel32:
+               case ld::Fixup::kindStoreX86PCRel8:
+               case ld::Fixup::kindStoreX86PCRel16:
+               case ld::Fixup::kindStoreX86PCRel32:
+               case ld::Fixup::kindStoreX86PCRel32_1:
+               case ld::Fixup::kindStoreX86PCRel32_2:
+               case ld::Fixup::kindStoreX86PCRel32_4:
+               case ld::Fixup::kindStoreX86PCRel32GOTLoad:
+               case ld::Fixup::kindStoreX86PCRel32GOTLoadNowLEA:
+               case ld::Fixup::kindStoreX86PCRel32GOT:
+               case ld::Fixup::kindStoreX86PCRel32TLVLoad:
+               case ld::Fixup::kindStoreX86PCRel32TLVLoadNowLEA:
+               case ld::Fixup::kindStoreARMBranch24:
+               case ld::Fixup::kindStoreThumbBranch22:
+               case ld::Fixup::kindStoreARMLoad12:
+               case ld::Fixup::kindStorePPCBranch24:
+               case ld::Fixup::kindStorePPCBranch14:
+               case ld::Fixup::kindStorePPCPicLow14:
+               case ld::Fixup::kindStorePPCPicLow16:
+               case ld::Fixup::kindStorePPCPicHigh16AddLow:
+               case ld::Fixup::kindStoreTargetAddressX86PCRel32:
+               case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
+               case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
+               case ld::Fixup::kindStoreTargetAddressARMBranch24:
+               case ld::Fixup::kindStoreTargetAddressThumbBranch22:
+               case ld::Fixup::kindStoreTargetAddressARMLoad12:
+               case ld::Fixup::kindStoreTargetAddressPPCBranch24:
+                       return true;
+               case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
+                       return (_options.outputKind() != Options::kKextBundle);
+               default:
+                       break;
+       }
+       return false;
+}
+
+bool OutputFile::isStore(ld::Fixup::Kind kind)
+{
+       switch ( kind ) { 
+               case ld::Fixup::kindNone:
+               case ld::Fixup::kindNoneFollowOn:
+               case ld::Fixup::kindNoneGroupSubordinate:
+               case ld::Fixup::kindNoneGroupSubordinateFDE:
+               case ld::Fixup::kindNoneGroupSubordinateLSDA:
+               case ld::Fixup::kindNoneGroupSubordinatePersonality:
+               case ld::Fixup::kindSetTargetAddress:
+               case ld::Fixup::kindSubtractTargetAddress:
+               case ld::Fixup::kindAddAddend:
+               case ld::Fixup::kindSubtractAddend:
+               case ld::Fixup::kindSetTargetImageOffset:
+               case ld::Fixup::kindSetTargetSectionOffset:
+                       return false;
+               default:
+                       break;
+       }
+       return true;
+}
+
+
+bool OutputFile::setsTarget(ld::Fixup::Kind kind)
+{
+       switch ( kind ) { 
+               case ld::Fixup::kindSetTargetAddress:
+               case ld::Fixup::kindLazyTarget:
+               case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+               case ld::Fixup::kindStoreTargetAddressLittleEndian64:
+               case ld::Fixup::kindStoreTargetAddressBigEndian32:
+               case ld::Fixup::kindStoreTargetAddressBigEndian64:
+               case ld::Fixup::kindStoreTargetAddressX86PCRel32:
+               case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
+               case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
+               case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
+               case ld::Fixup::kindStoreTargetAddressARMBranch24:
+               case ld::Fixup::kindStoreTargetAddressThumbBranch22:
+               case ld::Fixup::kindStoreTargetAddressARMLoad12:
+               case ld::Fixup::kindStoreTargetAddressPPCBranch24:
+                       return true;
+               case ld::Fixup::kindStoreX86DtraceCallSiteNop:
+               case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
+               case ld::Fixup::kindStoreARMDtraceCallSiteNop:
+               case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear:
+               case ld::Fixup::kindStoreThumbDtraceCallSiteNop:
+               case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
+               case ld::Fixup::kindStorePPCDtraceCallSiteNop:
+               case ld::Fixup::kindStorePPCDtraceIsEnableSiteClear:
+                       return (_options.outputKind() == Options::kObjectFile);
+               default:
+                       break;
+       }
+       return false;
+}
+
+bool OutputFile::isPointerToTarget(ld::Fixup::Kind kind)
+{
+       switch ( kind ) { 
+               case ld::Fixup::kindSetTargetAddress:
+               case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+               case ld::Fixup::kindStoreTargetAddressLittleEndian64:
+               case ld::Fixup::kindStoreTargetAddressBigEndian32:
+               case ld::Fixup::kindStoreTargetAddressBigEndian64:
+               case ld::Fixup::kindLazyTarget:
+                       return true;
+               default:
+                       break;
+       }
+       return false;
+}
+bool OutputFile::isPointerFromTarget(ld::Fixup::Kind kind)
+{
+       switch ( kind ) { 
+               case ld::Fixup::kindSubtractTargetAddress:
+                       return true;
+               default:
+                       break;
+       }
+       return false;
+}
+
+
+uint64_t OutputFile::lookBackAddend(ld::Fixup::iterator fit)
+{
+       uint64_t addend = 0;
+       switch ( fit->clusterSize ) {
+               case ld::Fixup::k1of1:
+               case ld::Fixup::k1of2:
+               case ld::Fixup::k2of2:
+                       break;
+               case ld::Fixup::k2of3:
+                       --fit;
+                       switch ( fit->kind ) {
+                               case ld::Fixup::kindAddAddend:
+                                       addend += fit->u.addend;
+                                       break;
+                               case ld::Fixup::kindSubtractAddend:
+                                       addend -= fit->u.addend;
+                                       break;
+                               default:
+                                       throw "unexpected fixup kind for binding";
+                       }
+                       break;
+               case ld::Fixup::k1of3:
+                       ++fit;
+                       switch ( fit->kind ) {
+                               case ld::Fixup::kindAddAddend:
+                                       addend += fit->u.addend;
+                                       break;
+                               case ld::Fixup::kindSubtractAddend:
+                                       addend -= fit->u.addend;
+                                       break;
+                               default:
+                                       throw "unexpected fixup kind for binding";
+                       }
+                       break;
+               default:
+                       throw "unexpected fixup cluster size for binding";
+       }
+       return addend;
+}
+
+
+
+
+
+void OutputFile::generateLinkEditInfo(ld::Internal& state)
+{
+       for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+               ld::Internal::FinalSection* sect = *sit;
+               bool objc1ClassRefSection = ( (sect->type() == ld::Section::typeCStringPointer) 
+                                                                       && (strcmp(sect->sectionName(), "__cls_refs") == 0)
+                                                                       && (strcmp(sect->segmentName(), "__OBJC") == 0) );
+               for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+                       const ld::Atom*         atom = *ait;
+                       
+                       // Record regular atoms that override a dylib's weak definitions 
+                       if ( (atom->scope() == ld::Atom::scopeGlobal) && atom->overridesDylibsWeakDef() ) {
+                               if ( _options.makeCompressedDyldInfo() ) {
+                                       uint8_t wtype = BIND_TYPE_OVERRIDE_OF_WEAKDEF_IN_DYLIB;
+                                       bool nonWeakDef = (atom->combine() == ld::Atom::combineNever);
+                                       _weakBindingInfo.push_back(BindingInfo(wtype, atom->name(), nonWeakDef, atom->finalAddress(), 0));
+                               }
+                               this->overridesWeakExternalSymbols = true;
+                               if ( _options.warnWeakExports() )
+                                       warning("overrides weak external symbol: %s", atom->name());
+                       }
+                       
+                       ld::Fixup*                      fixupWithTarget = NULL;
+                       ld::Fixup*                      fixupWithMinusTarget = NULL;
+                       ld::Fixup*                      fixupWithStore = NULL;
+                       const ld::Atom*         target = NULL;
+                       const ld::Atom*         minusTarget = NULL;
+                       uint64_t                        targetAddend = 0;
+                       uint64_t                        minusTargetAddend = 0;
+                       for (ld::Fixup::iterator fit = atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
+                               if ( fit->firstInCluster() ) {
+                                       fixupWithTarget = NULL;
+                                       fixupWithMinusTarget = NULL;
+                                       fixupWithStore = NULL;
+                                       target = NULL;
+                                       minusTarget = NULL;
+                                       targetAddend = 0;
+                                       minusTargetAddend = 0;
+                               }
+                               if ( this->setsTarget(fit->kind) ) {
+                                       switch ( fit->binding ) {
+                                               case ld::Fixup::bindingNone:
+                                               case ld::Fixup::bindingByNameUnbound:
+                                                       break;
+                                               case ld::Fixup::bindingByContentBound:
+                                               case ld::Fixup::bindingDirectlyBound:
+                                                       fixupWithTarget = fit;
+                                                       target = fit->u.target;
+                                                       break;
+                                               case ld::Fixup::bindingsIndirectlyBound:
+                                                       fixupWithTarget = fit;
+                                                       target = state.indirectBindingTable[fit->u.bindingIndex];
+                                                       break;
+                                       }
+                                       assert(target != NULL);
+                               }
+                               switch ( fit->kind ) {
+                                       case ld::Fixup::kindAddAddend:
+                                               targetAddend = fit->u.addend;
+                                               break;
+                                       case ld::Fixup::kindSubtractAddend:
+                                               minusTargetAddend = fit->u.addend;
+                                               break;
+                                       case ld::Fixup::kindSubtractTargetAddress:
+                                               switch ( fit->binding ) {
+                                                       case ld::Fixup::bindingNone:
+                                                       case ld::Fixup::bindingByNameUnbound:
+                                                               break;
+                                                       case ld::Fixup::bindingByContentBound:
+                                                       case ld::Fixup::bindingDirectlyBound:
+                                                               fixupWithMinusTarget = fit;
+                                                               minusTarget = fit->u.target;
+                                                               break;
+                                                       case ld::Fixup::bindingsIndirectlyBound:
+                                                               fixupWithMinusTarget = fit;
+                                                               minusTarget = state.indirectBindingTable[fit->u.bindingIndex];
+                                                               break;
+                                               }
+                                               assert(minusTarget != NULL);
+                                               break;
+                     default:
+                        break;    
+                               }
+                               if ( this->isStore(fit->kind) ) {
+                                       fixupWithStore = fit;
+                               }
+                               if ( fit->lastInCluster() ) {
+                                       if ( (fixupWithStore != NULL) && (target != NULL) ) {
+                                               if ( _options.outputKind() == Options::kObjectFile ) {
+                                                       this->addSectionRelocs(state, sect, atom, fixupWithTarget, fixupWithMinusTarget, fixupWithStore,
+                                                                                                       target, minusTarget, targetAddend, minusTargetAddend);
+                                               }
+                                               else {
+                                                       if ( _options.makeCompressedDyldInfo() ) {
+                                                               this->addDyldInfo(state, sect, atom, fixupWithTarget, fixupWithMinusTarget, fixupWithStore,
+                                                                                                       target, minusTarget, targetAddend, minusTargetAddend);
+                                                       }
+                                                       else { 
+                                                               this->addClassicRelocs(state, sect, atom, fixupWithTarget, fixupWithMinusTarget, fixupWithStore,
+                                                                                                       target, minusTarget, targetAddend, minusTargetAddend);
+                                                       }
+                                               }
+                                       }
+                                       else if ( objc1ClassRefSection && (target != NULL) && (fixupWithStore == NULL) ) {
+                                               // check for class refs to lazy loaded dylibs
+                                               const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(target->file());
+                                               if ( (dylib != NULL) && dylib->willBeLazyLoadedDylib() )
+                                                       throwf("illegal class reference to %s in lazy loaded dylib %s", target->name(), dylib->path());
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+
+void OutputFile::noteTextReloc(const ld::Atom* atom, const ld::Atom* target) 
+{
+       if ( (atom->contentType() == ld::Atom::typeStub) || (atom->contentType() == ld::Atom::typeStubHelper) ) {
+               // silently let stubs (synthesized by linker) use text relocs
+       }
+       else if ( _options.allowTextRelocs() ) {
+               if ( _options.warnAboutTextRelocs() )
+                       warning("text reloc in %s to %s", atom->name(), target->name());
+       } 
+       else if ( _options.positionIndependentExecutable() && (_options.iphoneOSVersionMin() >= ld::iPhone4_3) ) {
+               if ( ! this->pieDisabled ) {
+                       warning("PIE disabled. Absolute addressing (perhaps -mdynamic-no-pic) not allowed in code signed PIE, "
+                               "but used in %s from %s. " 
+                               "To fix this warning, don't compile with -mdynamic-no-pic or link with -Wl,-no_pie", 
+                               atom->name(), atom->file()->path());
+               }
+               this->pieDisabled = true;
+       }
+       else {
+               throwf("illegal text reloc to %s from %s in %s", target->name(), target->file()->path(), atom->name());
+       }
+}
+
+void OutputFile::addDyldInfo(ld::Internal& state,  ld::Internal::FinalSection* sect, const ld::Atom* atom,  
+                                                               ld::Fixup* fixupWithTarget, ld::Fixup* fixupWithMinusTarget, ld::Fixup* fixupWithStore,
+                                                               const ld::Atom* target, const ld::Atom* minusTarget, 
+                                                               uint64_t targetAddend, uint64_t minusTargetAddend)
+{
+       if ( sect->isSectionHidden() )
+               return;
+
+       // no need to rebase or bind PCRel stores
+       if ( this->isPcRelStore(fixupWithStore->kind) ) {
+               // as long as target is in same linkage unit
+               if ( (target == NULL) || (target->definition() != ld::Atom::definitionProxy) )
+                       return;
+       }
+
+       // no need to rebase or bind PIC internal pointer diff
+       if ( minusTarget != NULL ) {
+               // with pointer diffs, both need to be in same linkage unit
+               assert(minusTarget->definition() != ld::Atom::definitionProxy);
+               assert(target != NULL);
+               assert(target->definition() != ld::Atom::definitionProxy);
+               if ( target == minusTarget ) {
+                       // This is a compile time constant and could have been optimized away by compiler
+                       return;
+               }
+               
+               // make sure target is not global and weak
+               if ( (target->scope() == ld::Atom::scopeGlobal) && (target->combine() == ld::Atom::combineByName)
+                               && (atom->section().type() != ld::Section::typeCFI)
+                               && (atom->section().type() != ld::Section::typeDtraceDOF)
+                               && (atom->section().type() != ld::Section::typeUnwindInfo) ) {
+                       // ok for __eh_frame and __uwind_info to use pointer diffs to global weak symbols
+                       throwf("bad codegen, pointer diff in %s to global weak symbol %s", atom->name(), target->name());
+               }
+               return;
+       }
+
+       // no need to rebase or bind an atom's references to itself if the output is not slidable
+       if ( (atom == target) && !_options.outputSlidable() )
+               return;
+
+       // cluster has no target, so needs no rebasing or binding       
+       if ( target == NULL )
+               return; 
+
+       bool inReadOnlySeg = ( strcmp(sect->segmentName(), "__TEXT") == 0 );
+       bool needsRebase = false;
+       bool needsBinding = false;
+       bool needsLazyBinding = false;
+       bool needsWeakBinding = false;
+
+       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->willBeWeakLinked()));
+       uint64_t address =  atom->finalAddress() + fixupWithTarget->offsetInAtom;
+       uint64_t addend = targetAddend - minusTargetAddend;
+
+       // special case lazy pointers
+       if ( fixupWithTarget->kind == ld::Fixup::kindLazyTarget ) {
+               assert(fixupWithTarget->u.target == target);
+               assert(addend == 0);
+               // lazy dylib lazy pointers do not have any dyld info
+               if ( atom->section().type() == ld::Section::typeLazyDylibPointer )
+                       return;
+               // lazy binding to weak definitions are done differently
+               // they are directly bound to target, then have a weak bind in case of a collision
+               if ( target->combine() == ld::Atom::combineByName ) {
+                       if ( target->definition() == ld::Atom::definitionProxy ) {
+                               // weak def exported from another dylib
+                               // must non-lazy bind to it plus have weak binding info in case of collision
+                               needsBinding = true;
+                               needsWeakBinding = true;
+                       }
+                       else {
+                               // weak def in this linkage unit.  
+                               // just rebase, plus have weak binding info in case of collision
+                               // this will be done by other cluster on lazy pointer atom
+                       }
+               }
+               else if ( (target->contentType() == ld::Atom::typeResolver) && (target->scope() != ld::Atom::scopeGlobal) ) {
+                       // <rdar://problem/8553647> Hidden resolver functions should not have lazy binding info
+                       needsLazyBinding = false;
+               }
+               else {
+                       // normal case of a pointer to non-weak-def symbol, so can lazily bind
+                       needsLazyBinding = true;
+               }
+       }
+       else {
+               // everything except lazy pointers
+               switch ( target->definition() ) {
+                       case ld::Atom::definitionProxy:
+                               if ( (dylib != NULL) && dylib->willBeLazyLoadedDylib() )
+                                       throwf("illegal data reference to %s in lazy loaded dylib %s", target->name(), dylib->path());
+                               if ( target->contentType() == ld::Atom::typeTLV ) {
+                                       if ( sect->type() != ld::Section::typeTLVPointers )
+                                               throwf("illegal data reference in %s to thread local variable %s in dylib %s", 
+                                                               atom->name(), target->name(), dylib->path());
+                               }
+                               if ( inReadOnlySeg ) 
+                                       type = BIND_TYPE_TEXT_ABSOLUTE32;
+                               needsBinding = true;
+                               if ( target->combine() == ld::Atom::combineByName ) 
+                                       needsWeakBinding = true;
+                               break;
+                       case ld::Atom::definitionRegular:
+                       case ld::Atom::definitionTentative:
+                               // only slideable images need rebasing info
+                               if ( _options.outputSlidable() ) {
+                                       needsRebase = true;
+                               }
+                               // references to internal symbol never need binding
+                               if ( target->scope() != ld::Atom::scopeGlobal ) 
+                                       break;
+                               // reference to global weak def needs weak binding
+                               if ( (target->combine() == ld::Atom::combineByName) && (target->definition() == ld::Atom::definitionRegular) )
+                                       needsWeakBinding = true;
+                               else if ( _options.outputKind() == Options::kDynamicExecutable ) {
+                                       // in main executables, the only way regular symbols are indirected is if -interposable is used
+                                       if ( _options.interposable(target->name()) ) {
+                                               needsRebase = false;
+                                               needsBinding = true;
+                                       }
+                               }
+                               else {
+                                       // for flat-namespace or interposable two-level-namespace
+                                       // all references to exported symbols get indirected
+                                       if ( (_options.nameSpace() != Options::kTwoLevelNameSpace) || _options.interposable(target->name()) ) {
+                                               // <rdar://problem/5254468> no external relocs for flat objc classes
+                                               if ( strncmp(target->name(), ".objc_class_", 12) == 0 )
+                                                       break;
+                                               // no rebase info for references to global symbols that will have binding info
+                                               needsRebase = false;
+                                               needsBinding = true;
+                                       }
+                               }
+                               break;
+                       case ld::Atom::definitionAbsolute:
+                               break;
+               }
+       }
+       
+       // record dyld info for this cluster
+       if ( needsRebase ) {
+               if ( inReadOnlySeg ) {
+                       noteTextReloc(atom, target);
+                       sect->hasLocalRelocs = true;  // so dyld knows to change permissions on __TEXT segment
+                       rebaseType = REBASE_TYPE_TEXT_ABSOLUTE32;
+               }
+               _rebaseInfo.push_back(RebaseInfo(rebaseType, address));
+       }
+       if ( needsBinding ) {
+               if ( inReadOnlySeg ) {
+                       noteTextReloc(atom, target);
+                       sect->hasExternalRelocs = true; // so dyld knows to change permissions on __TEXT segment
+               }
+               _bindingInfo.push_back(BindingInfo(type, this->compressedOrdinalForAtom(target), target->name(), weak_import, address, addend));
+       }
+       if ( needsLazyBinding ) {
+               if ( _options.bindAtLoad() )
+                       _bindingInfo.push_back(BindingInfo(type, this->compressedOrdinalForAtom(target), target->name(), weak_import, address, addend));
+               else
+                       _lazyBindingInfo.push_back(BindingInfo(type, this->compressedOrdinalForAtom(target), target->name(), weak_import, address, addend));
+       }
+       if ( needsWeakBinding )
+               _weakBindingInfo.push_back(BindingInfo(type, 0, target->name(), false, address, addend));
+
+       // record if weak imported  
+       if ( weak_import && (target->definition() == ld::Atom::definitionProxy) )
+               (const_cast<ld::Atom*>(target))->setWeakImported();
+}
+
+
+void OutputFile::addClassicRelocs(ld::Internal& state, ld::Internal::FinalSection* sect, const ld::Atom* atom, 
+                                                               ld::Fixup* fixupWithTarget, ld::Fixup* fixupWithMinusTarget, ld::Fixup* fixupWithStore,
+                                                               const ld::Atom* target, const ld::Atom* minusTarget, 
+                                                               uint64_t targetAddend, uint64_t minusTargetAddend)
+{
+       if ( sect->isSectionHidden() )
+               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);
+               // record if weak imported  
+               const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(target->file());
+               if ( (dylib != NULL) && (fixupWithTarget->weakImport || dylib->willBeWeakLinked()) )
+                       (const_cast<ld::Atom*>(target))->setWeakImported();
+               return;
+       }
+       
+       // no need to rebase or bind PCRel stores
+       if ( this->isPcRelStore(fixupWithStore->kind) ) {
+               // as long as target is in same linkage unit
+               if ( (target == NULL) || (target->definition() != ld::Atom::definitionProxy) )
+                       return;
+       }
+
+       // no need to rebase or bind PIC internal pointer diff
+       if ( minusTarget != NULL ) {
+               // with pointer diffs, both need to be in same linkage unit
+               assert(minusTarget->definition() != ld::Atom::definitionProxy);
+               assert(target != NULL);
+               assert(target->definition() != ld::Atom::definitionProxy);
+               // make sure target is not global and weak
+               if ( (target->scope() == ld::Atom::scopeGlobal) && (target->combine() == ld::Atom::combineByName)
+                               && (atom->section().type() != ld::Section::typeCFI)
+                               && (atom->section().type() != ld::Section::typeDtraceDOF)
+                               && (atom->section().type() != ld::Section::typeUnwindInfo) 
+                               && (minusTarget != target) ) {
+                       // ok for __eh_frame and __uwind_info to use pointer diffs to global weak symbols
+                       throwf("bad codegen, pointer diff in %s to global weak symbol %s", atom->name(), target->name());
+               }
+               return;
+       }
+
+       // cluster has no target, so needs no rebasing or binding       
+       if ( target == NULL )
+               return; 
+
+       assert(_localRelocsAtom != NULL);
+       uint64_t relocAddress =  atom->finalAddress() + fixupWithTarget->offsetInAtom - _localRelocsAtom->relocBaseAddress(state);
+
+       bool inReadOnlySeg = ( strcmp(sect->segmentName(), "__TEXT") == 0 );
+       bool needsLocalReloc = false;
+       bool needsExternReloc = false;
+
+       switch ( fixupWithStore->kind ) {
+               case ld::Fixup::kindLazyTarget:
+                       {
+                               // lazy pointers don't need relocs, but might need weak_import bit set
+                               const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(target->file());
+                               if ( (dylib != NULL) && (fixupWithTarget->weakImport || dylib->willBeWeakLinked()) )
+                                       (const_cast<ld::Atom*>(target))->setWeakImported();
+                       }
+                       break;
+               case ld::Fixup::kindStoreLittleEndian32:
+               case ld::Fixup::kindStoreLittleEndian64:
+               case ld::Fixup::kindStoreBigEndian32:
+               case ld::Fixup::kindStoreBigEndian64:
+               case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+               case ld::Fixup::kindStoreTargetAddressLittleEndian64:
+               case ld::Fixup::kindStoreTargetAddressBigEndian32:
+               case ld::Fixup::kindStoreTargetAddressBigEndian64:
+                       // is pointer 
+                       switch ( target->definition() ) {
+                               case ld::Atom::definitionProxy:
+                                       needsExternReloc = true;
+                                       break;
+                               case ld::Atom::definitionRegular:
+                               case ld::Atom::definitionTentative:
+                                       // only slideable images need local relocs
+                                       if ( _options.outputSlidable() ) 
+                                               needsLocalReloc = true;
+                                       // references to internal symbol never need binding
+                                       if ( target->scope() != ld::Atom::scopeGlobal ) 
+                                               break;
+                                       // reference to global weak def needs weak binding in dynamic images
+                                       if ( (target->combine() == ld::Atom::combineByName) 
+                                               && (target->definition() == ld::Atom::definitionRegular)
+                                               && (_options.outputKind() != Options::kStaticExecutable) ) {
+                                               needsExternReloc = true;
+                                       }
+                                       else if ( _options.outputKind() == Options::kDynamicExecutable ) {
+                                               // in main executables, the only way regular symbols are indirected is if -interposable is used
+                                               if ( _options.interposable(target->name()) ) 
+                                                       needsExternReloc = true;
+                                       }
+                                       else {
+                                               // for flat-namespace or interposable two-level-namespace
+                                               // all references to exported symbols get indirected
+                                               if ( (_options.nameSpace() != Options::kTwoLevelNameSpace) || _options.interposable(target->name()) ) {
+                                                       // <rdar://problem/5254468> no external relocs for flat objc classes
+                                                       if ( strncmp(target->name(), ".objc_class_", 12) == 0 )
+                                                               break;
+                                                       // no rebase info for references to global symbols that will have binding info
+                                                       needsExternReloc = true;
+                                               }
+                                       }
+                                       if ( needsExternReloc )
+                                               needsLocalReloc = false;
+                                       break;
+                               case ld::Atom::definitionAbsolute:
+                                       break;
+                       }
+                       if ( needsExternReloc ) {
+                               if ( inReadOnlySeg )
+                                       noteTextReloc(atom, target);
+                               const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(target->file());
+                               if ( (dylib != NULL) && dylib->willBeLazyLoadedDylib() )
+                                       throwf("illegal data reference to %s in lazy loaded dylib %s", target->name(), dylib->path());
+                               _externalRelocsAtom->addExternalPointerReloc(relocAddress, target);
+                               sect->hasExternalRelocs = true;
+                               fixupWithTarget->contentAddendOnly = true;
+                               // record if weak imported  
+                               if ( (dylib != NULL) && (fixupWithTarget->weakImport || dylib->willBeWeakLinked()) )
+                                       (const_cast<ld::Atom*>(target))->setWeakImported();
+                       }
+                       else if ( needsLocalReloc ) {
+                               assert(target != NULL);
+                               if ( inReadOnlySeg )
+                                       noteTextReloc(atom, target);
+                               _localRelocsAtom->addPointerReloc(relocAddress, target->machoSection());
+                               sect->hasLocalRelocs = true;
+                       }
+                       break;
+               case ld::Fixup::kindStorePPCAbsLow14:
+               case ld::Fixup::kindStorePPCAbsLow16:
+               case ld::Fixup::kindStorePPCAbsHigh16AddLow:
+               case ld::Fixup::kindStorePPCAbsHigh16:
+                       {
+                               assert(target != NULL);
+                               if ( target->definition() == ld::Atom::definitionProxy )
+                                       throwf("half word text relocs not supported in %s", atom->name());
+                               if ( _options.outputSlidable() ) {
+                                       if ( inReadOnlySeg )
+                                               noteTextReloc(atom, target);
+                                       uint32_t machoSectionIndex = (target->definition() == ld::Atom::definitionAbsolute) 
+                                                                                                       ? R_ABS : target->machoSection();
+                                       _localRelocsAtom->addTextReloc(relocAddress, fixupWithTarget->kind,  
+                                                                                                       target->finalAddress(), machoSectionIndex);
+                                       sect->hasLocalRelocs = true;
+                               }
+                       }
+                       break;
+               case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
+                       if ( _options.outputKind() == Options::kKextBundle ) {
+                               assert(target != NULL);
+                               if ( target->definition() == ld::Atom::definitionProxy ) {
+                                       _externalRelocsAtom->addExternalCallSiteReloc(relocAddress, target);
+                                       fixupWithStore->contentAddendOnly = true;
+                               }
+                       }
+                       break;
+               default:
+                       break;
+       }
+}
+
+
+bool OutputFile::useExternalSectionReloc(const ld::Atom* atom, const ld::Atom* target, ld::Fixup* fixupWithTarget)
+{
+       if ( _options.architecture() == CPU_TYPE_X86_64 ) {
+               // x86_64 uses external relocations for everthing that has a symbol
+               return ( target->symbolTableInclusion() != ld::Atom::symbolTableNotIn );
+       }
+       // most architectures use external relocations only for references
+       // to a symbol in another translation unit or for references to "weak symbols" or tentative definitions
+       assert(target != NULL);
+       if ( target->definition() == ld::Atom::definitionProxy )
+               return true;
+       if ( (target->definition() == ld::Atom::definitionTentative) && ! _options.makeTentativeDefinitionsReal() )
+               return true;
+       if ( target->scope() != ld::Atom::scopeGlobal )
+               return false;
+       if ( (target->combine() == ld::Atom::combineByName) && (target->definition() == ld::Atom::definitionRegular) )
+               return true;
+       return false;
+}
+
+
+
+
+void OutputFile::addSectionRelocs(ld::Internal& state, ld::Internal::FinalSection* sect, const ld::Atom* atom, 
+                                                               ld::Fixup* fixupWithTarget, ld::Fixup* fixupWithMinusTarget, ld::Fixup* fixupWithStore,
+                                                               const ld::Atom* target, const ld::Atom* minusTarget, 
+                                                               uint64_t targetAddend, uint64_t minusTargetAddend)
+{
+       if ( sect->isSectionHidden() )
+               return;
+       
+       // in -r mode where there will be no labels on __eh_frame section, there is no need for relocations
+       if ( (sect->type() == ld::Section::typeCFI) && _options.removeEHLabels() )
+               return;
+               
+       // non-lazy-pointer section is encoded in indirect symbol table - not using relocations
+       if ( sect->type() == ld::Section::typeNonLazyPointer ) 
+               return;
+
+       // tentative defs don't have any relocations
+       if ( sect->type() == ld::Section::typeTentativeDefs ) 
+               return;
+
+       assert(target != NULL);
+       assert(fixupWithTarget != NULL);
+       bool targetUsesExternalReloc = this->useExternalSectionReloc(atom, target, fixupWithTarget);
+       bool minusTargetUsesExternalReloc = (minusTarget != NULL) && this->useExternalSectionReloc(atom, minusTarget, fixupWithMinusTarget);
+       
+       // in x86_64 .o files an external reloc means the content contains just the addend
+       if ( _options.architecture() == CPU_TYPE_X86_64 ) {
+               if ( targetUsesExternalReloc ) {
+                       fixupWithTarget->contentAddendOnly = true;
+                       fixupWithStore->contentAddendOnly = true;
+               }
+               if ( minusTargetUsesExternalReloc )
+                       fixupWithMinusTarget->contentAddendOnly = true;
+       }
+       else {
+               // for other archs, content is addend only with (non pc-rel) pointers
+               // pc-rel instructions are funny. If the target is _foo+8 and _foo is 
+               // external, then the pc-rel instruction *evalutates* to the address 8.
+               if ( targetUsesExternalReloc ) {
+                       if ( isPcRelStore(fixupWithStore->kind) ) {
+                               fixupWithTarget->contentDetlaToAddendOnly = true;
+                               fixupWithStore->contentDetlaToAddendOnly = true;
+                       }
+                       else if ( minusTarget == NULL ){
+                               fixupWithTarget->contentAddendOnly = true;
+                               fixupWithStore->contentAddendOnly = true;
+                       }
+               }
+       }
+       
+       if ( fixupWithStore != NULL ) {
+               _sectionsRelocationsAtom->addSectionReloc(sect, fixupWithStore->kind, atom, fixupWithStore->offsetInAtom, 
+                                                                                                       targetUsesExternalReloc, minusTargetUsesExternalReloc,
+                                                                                                       target, targetAddend, minusTarget, minusTargetAddend);
+       }
+
+}
+
+
+void OutputFile::makeSplitSegInfo(ld::Internal& state)
+{
+       if ( !_options.sharedRegionEligible() )
+               return;
+               
+       for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+               ld::Internal::FinalSection* sect = *sit;
+               if ( sect->isSectionHidden() )
+                       continue;
+               if ( strcmp(sect->segmentName(), "__TEXT") != 0 )
+                       continue;
+               for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+                       const ld::Atom* atom = *ait;
+                       const ld::Atom* target = NULL;
+                       bool hadSubtract = false;
+                       for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+                               if ( fit->firstInCluster() ) 
+                                       target = NULL;
+                               if ( fit->kind == ld::Fixup::kindSubtractTargetAddress ) {
+                                       hadSubtract = true;
+                                       continue;
+                               }
+                               switch ( fit->binding ) {
+                                       case ld::Fixup::bindingNone:
+                                       case ld::Fixup::bindingByNameUnbound:
+                                               break;
+                                       case ld::Fixup::bindingByContentBound:
+                                       case ld::Fixup::bindingDirectlyBound:
+                                               target = fit->u.target;
+                                               break;
+                                       case ld::Fixup::bindingsIndirectlyBound:
+                                               target = state.indirectBindingTable[fit->u.bindingIndex];
+                                               break;
+                               }
+                               switch ( fit->kind ) {
+                                       case ld::Fixup::kindStoreBigEndian32:
+                                       case ld::Fixup::kindStoreLittleEndian32:
+                                       case ld::Fixup::kindStoreLittleEndian64:
+                                       case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+                                       case ld::Fixup::kindStoreTargetAddressLittleEndian64:
+                                               // if no subtract, then this is an absolute pointer which means
+                                               // there is also a text reloc which update_dyld_shared_cache will use.
+                                               if ( ! hadSubtract )
+                                                       break;
+                                       case ld::Fixup::kindStoreX86PCRel32:
+                                       case ld::Fixup::kindStoreX86PCRel32_1:
+                                       case ld::Fixup::kindStoreX86PCRel32_2:
+                                       case ld::Fixup::kindStoreX86PCRel32_4:
+                                       case ld::Fixup::kindStoreX86PCRel32GOTLoad:
+                                       case ld::Fixup::kindStoreX86PCRel32GOTLoadNowLEA:
+                                       case ld::Fixup::kindStoreX86PCRel32GOT:
+                                       case ld::Fixup::kindStorePPCPicHigh16AddLow:
+                                       case ld::Fixup::kindStoreTargetAddressX86PCRel32:
+                                       case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
+                                       case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
+                                               assert(target != NULL);
+                                               if ( strcmp(sect->segmentName(), target->section().segmentName()) != 0 ) {      
+                                                       _splitSegInfos.push_back(SplitSegInfoEntry(atom->finalAddress()+fit->offsetInAtom,fit->kind));
+                                               }
+                                               break;
+                                       default:
+                                               break;
+                               }
+                       }
+               }
+       }
+}
+
+
+void OutputFile::writeMapFile(ld::Internal& state)
+{
+       if ( _options.generatedMapPath() != NULL ) {
+               FILE* mapFile = fopen(_options.generatedMapPath(), "w"); 
+               if ( mapFile != NULL ) {
+                       // write output path
+                       fprintf(mapFile, "# Path: %s\n", _options.outputFilePath());
+                       // write output architecure
+                       fprintf(mapFile, "# Arch: %s\n", _options.architectureName());
+                       // write UUID
+                       //if ( fUUIDAtom != NULL ) {
+                       //      const uint8_t* uuid = fUUIDAtom->getUUID();
+                       //      fprintf(mapFile, "# UUID: %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X \n",
+                       //              uuid[0], uuid[1], uuid[2],  uuid[3],  uuid[4],  uuid[5],  uuid[6],  uuid[7],
+                       //              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*, uint32_t> readerToFileOrdinal;
+                       for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+                               ld::Internal::FinalSection* sect = *sit;
+                               if ( sect->isSectionHidden() ) 
+                                       continue;
+                               for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+                                       const ld::Atom* atom = *ait;
+                                       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);
+                                       if ( pos == readerToOrdinal.end() ) {
+                                               readerToOrdinal[reader] = readerOrdinal;
+                                               ordinalToReader[readerOrdinal] = reader;
+                                       }
+                               }
+                       }
+                       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++;
+                               }
+                       }
+                       // write table of sections
+                       fprintf(mapFile, "# Sections:\n");
+                       fprintf(mapFile, "# Address\tSize    \tSegment\tSection\n"); 
+                       for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+                               ld::Internal::FinalSection* sect = *sit;
+                               if ( sect->isSectionHidden() ) 
+                                       continue;
+                               fprintf(mapFile, "0x%08llX\t0x%08llX\t%s\t%s\n", sect->address, sect->size, 
+                                                       sect->segmentName(), sect->sectionName());
+                       }
+                       // write table of symbols
+                       fprintf(mapFile, "# Symbols:\n");
+                       fprintf(mapFile, "# Address\tSize    \tFile  Name\n"); 
+                       for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+                               ld::Internal::FinalSection* sect = *sit;
+                               if ( sect->isSectionHidden() ) 
+                                       continue;
+                               //bool isCstring = (sect->type() == ld::Section::typeCString);
+                               for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+                                       char buffer[4096];
+                                       const ld::Atom* atom = *ait;
+                                       const char* name = atom->name();
+                                       if ( atom->contentType() == ld::Atom::typeCString ) {
+                                               strcpy(buffer, "literal string: ");
+                                               strlcat(buffer, (char*)atom->rawContentPointer(), 4096);
+                                               name = buffer;
+                                       }
+                                       else if ( (atom->contentType() == ld::Atom::typeCFI) && (strcmp(name, "FDE") == 0) ) {
+                                               for (ld::Fixup::iterator fit = atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
+                                                       if ( (fit->kind == ld::Fixup::kindSetTargetAddress) && (fit->clusterSize == ld::Fixup::k1of4) ) {
+                                                               assert(fit->binding == ld::Fixup::bindingDirectlyBound);
+                                                               if ( fit->u.target->section().type() == ld::Section::typeCode) {
+                                                                       strcpy(buffer, "FDE for: ");
+                                                                       strlcat(buffer, fit->u.target->name(), 4096);
+                                                                       name = buffer;
+                                                               }
+                                                       }
+                                               }
+                                       }
+                                       else if ( atom->contentType() == ld::Atom::typeNonLazyPointer ) {
+                                               strcpy(buffer, "non-lazy-pointer");
+                                               for (ld::Fixup::iterator fit = atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
+                                                       if ( fit->binding == ld::Fixup::bindingsIndirectlyBound ) {
+                                                               strcpy(buffer, "non-lazy-pointer-to: ");
+                                                               strlcat(buffer, state.indirectBindingTable[fit->u.bindingIndex]->name(), 4096);
+                                                               break;
+                                                       }
+                                                       else if ( fit->binding == ld::Fixup::bindingDirectlyBound ) {
+                                                               strcpy(buffer, "non-lazy-pointer-to-local: ");
+                                                               strlcat(buffer, fit->u.target->name(), 4096);
+                                                               break;
+                                                       }
+                                               }
+                                               name = buffer;
+                                       }
+                                       fprintf(mapFile, "0x%08llX\t0x%08llX\t[%3u] %s\n", atom->finalAddress(), atom->size(), 
+                                                       readerToFileOrdinal[atom->file()], name);
+                               }
+                       }
+                       fclose(mapFile);
+               }
+               else {
+                       warning("could not write map file: %s\n", _options.generatedMapPath());
+               }
+       }
+}
+
+
+// used to sort atoms with debug notes
+class DebugNoteSorter
+{
+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();
+               if ( leftFileOrdinal!= rightFileOrdinal)
+                       return (leftFileOrdinal < rightFileOrdinal);
+
+               // then sort by atom objectAddress
+               uint64_t leftAddr  = left->objectAddress();
+               uint64_t rightAddr = right->objectAddress();
+               return leftAddr < rightAddr;
+       }
+};
+
+
+class CStringEquals
+{
+public:
+       bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+};
+
+const char* OutputFile::assureFullPath(const char* path)
+{
+       if ( path[0] == '/' )
+               return path;
+       char cwdbuff[MAXPATHLEN];
+       if ( getcwd(cwdbuff, MAXPATHLEN) != NULL ) {
+               char* result;
+               asprintf(&result, "%s/%s", cwdbuff, path);
+               if ( result != NULL )
+                       return result;
+       }
+       return path;
+}
+
+void OutputFile::synthesizeDebugNotes(ld::Internal& state)
+{
+       // -S means don't synthesize debug map
+       if ( _options.debugInfoStripping() == Options::kDebugInfoNone )
+               return;
+       // make a vector of atoms that come from files compiled with dwarf debug info
+       std::vector<const ld::Atom*> atomsNeedingDebugNotes;
+       std::set<const ld::Atom*> atomsWithStabs;
+       atomsNeedingDebugNotes.reserve(1024);
+       const ld::relocatable::File* objFile = NULL;
+       bool objFileHasDwarf = false;
+       bool objFileHasStabs = false;
+       for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.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;
+                       // no stabs for atoms that would not be in the symbol table
+                       if ( atom->symbolTableInclusion() == ld::Atom::symbolTableNotIn )
+                               continue;
+                       if ( atom->symbolTableInclusion() == ld::Atom::symbolTableNotInFinalLinkedImages )
+                               continue;
+                       // no stabs for absolute symbols
+                       if ( atom->definition() == ld::Atom::definitionAbsolute ) 
+                               continue;
+                       // no stabs for .eh atoms
+                       if ( atom->contentType() == ld::Atom::typeCFI )
+                               continue;
+                       const ld::File* file = atom->file();
+                       if ( file != NULL ) {
+                               if ( file != objFile ) {
+                                       objFileHasDwarf = false;
+                                       objFileHasStabs = false;
+                                       objFile = dynamic_cast<const ld::relocatable::File*>(file);
+                                       if ( objFile != NULL ) {
+                                               switch ( objFile->debugInfo() ) {
+                                                       case ld::relocatable::File::kDebugInfoNone:
+                                                               break;
+                                                       case ld::relocatable::File::kDebugInfoDwarf:
+                                                               objFileHasDwarf = true;
+                                                               break;
+                                                       case ld::relocatable::File::kDebugInfoStabs:
+                                                       case ld::relocatable::File::kDebugInfoStabsUUID:
+                                                               objFileHasStabs = true;
+                                                               break;
+                                               }
+                                       }
+                               }
+                               if ( objFileHasDwarf )
+                                       atomsNeedingDebugNotes.push_back(atom);
+                               if ( objFileHasStabs )
+                                       atomsWithStabs.insert(atom);
+                       }
+               }
+       }
+       
+       // sort by file ordinal then atom ordinal
+       std::sort(atomsNeedingDebugNotes.begin(), atomsNeedingDebugNotes.end(), DebugNoteSorter());
+
+       // synthesize "debug notes" and add them to master stabs vector
+       const char* dirPath = NULL;
+       const char* filename = NULL;
+       bool wroteStartSO = false;
+       state.stabs.reserve(atomsNeedingDebugNotes.size()*4);
+       __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals>  seenFiles;
+       for (std::vector<const ld::Atom*>::iterator it=atomsNeedingDebugNotes.begin(); it != atomsNeedingDebugNotes.end(); it++) {
+               const ld::Atom* atom = *it;
+               const ld::File* atomFile = atom->file();
+               const ld::relocatable::File* atomObjFile = dynamic_cast<const ld::relocatable::File*>(atomFile);
+               const char* newDirPath;
+               const char* newFilename;
+               //fprintf(stderr, "debug note for %s\n", atom->getDisplayName());
+               if ( atom->translationUnitSource(&newDirPath, &newFilename) ) {
+                       // 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] != '/') )
+                                       asprintf((char**)&newDirPath, "%s/", newDirPath);
+                               if ( filename != NULL ) {
+                                       // translation unit change, emit ending SO
+                                       ld::relocatable::File::Stab endFileStab;
+                                       endFileStab.atom                = NULL;
+                                       endFileStab.type                = N_SO;
+                                       endFileStab.other               = 1;
+                                       endFileStab.desc                = 0;
+                                       endFileStab.value               = 0;
+                                       endFileStab.string              = "";
+                                       state.stabs.push_back(endFileStab);
+                               }
+                               // new translation unit, emit start SO's
+                               ld::relocatable::File::Stab dirPathStab;
+                               dirPathStab.atom                = NULL;
+                               dirPathStab.type                = N_SO;
+                               dirPathStab.other               = 0;
+                               dirPathStab.desc                = 0;
+                               dirPathStab.value               = 0;
+                               dirPathStab.string              = newDirPath;
+                               state.stabs.push_back(dirPathStab);
+                               ld::relocatable::File::Stab fileStab;
+                               fileStab.atom           = NULL;
+                               fileStab.type           = N_SO;
+                               fileStab.other          = 0;
+                               fileStab.desc           = 0;
+                               fileStab.value          = 0;
+                               fileStab.string         = newFilename;
+                               state.stabs.push_back(fileStab);
+                               // Synthesize OSO for start of file
+                               ld::relocatable::File::Stab objStab;
+                               objStab.atom            = NULL;
+                               objStab.type            = N_OSO;
+                               // <rdar://problem/6337329> linker should put cpusubtype in n_sect field of nlist entry for N_OSO debug note entries
+                               objStab.other           = atomFile->cpuSubType(); 
+                               objStab.desc            = 1;
+                               if ( atomObjFile != NULL ) {
+                                       objStab.string  = assureFullPath(atomObjFile->debugInfoPath());
+                                       objStab.value   = atomObjFile->debugInfoModificationTime();
+                               }
+                               else {
+                                       objStab.string  = assureFullPath(atomFile->path());
+                                       objStab.value   = atomFile->modificationTime();
+                               }
+                               state.stabs.push_back(objStab);
+                               wroteStartSO = true;
+                               // add the source file path to seenFiles so it does not show up in SOLs
+                               seenFiles.insert(newFilename);
+                               char* fullFilePath;
+                               asprintf(&fullFilePath, "%s/%s", newDirPath, newFilename);
+                               // add both leaf path and full path
+                               seenFiles.insert(fullFilePath);
+                       }
+                       filename = newFilename;
+                       dirPath = newDirPath;
+                       if ( atom->section().type() == ld::Section::typeCode ) {
+                               // Synthesize BNSYM and start FUN stabs
+                               ld::relocatable::File::Stab beginSym;
+                               beginSym.atom           = atom;
+                               beginSym.type           = N_BNSYM;
+                               beginSym.other          = 1;
+                               beginSym.desc           = 0;
+                               beginSym.value          = 0;
+                               beginSym.string         = "";
+                               state.stabs.push_back(beginSym);
+                               ld::relocatable::File::Stab startFun;
+                               startFun.atom           = atom;
+                               startFun.type           = N_FUN;
+                               startFun.other          = 1;
+                               startFun.desc           = 0;
+                               startFun.value          = 0;
+                               startFun.string         = atom->name();
+                               state.stabs.push_back(startFun);
+                               // Synthesize any SOL stabs needed
+                               const char* curFile = NULL;
+                               for (ld::Atom::LineInfo::iterator lit = atom->beginLineInfo(); lit != atom->endLineInfo(); ++lit) {
+                                       if ( lit->fileName != curFile ) {
+                                               if ( seenFiles.count(lit->fileName) == 0 ) {
+                                                       seenFiles.insert(lit->fileName);
+                                                       ld::relocatable::File::Stab sol;
+                                                       sol.atom                = 0;
+                                                       sol.type                = N_SOL;
+                                                       sol.other               = 0;
+                                                       sol.desc                = 0;
+                                                       sol.value               = 0;
+                                                       sol.string              = lit->fileName;
+                                                       state.stabs.push_back(sol);
+                                               }
+                                               curFile = lit->fileName;
+                                       }
+                               }
+                               // Synthesize end FUN and ENSYM stabs
+                               ld::relocatable::File::Stab endFun;
+                               endFun.atom                     = atom;
+                               endFun.type                     = N_FUN;
+                               endFun.other            = 0;
+                               endFun.desc                     = 0;
+                               endFun.value            = 0;
+                               endFun.string           = "";
+                               state.stabs.push_back(endFun);
+                               ld::relocatable::File::Stab endSym;
+                               endSym.atom                     = atom;
+                               endSym.type                     = N_ENSYM;
+                               endSym.other            = 1;
+                               endSym.desc                     = 0;
+                               endSym.value            = 0;
+                               endSym.string           = "";
+                               state.stabs.push_back(endSym);
+                       }
+                       else {
+                               ld::relocatable::File::Stab globalsStab;
+                               const char* name = atom->name();
+                               if ( atom->scope() == ld::Atom::scopeTranslationUnit ) {
+                                       // Synthesize STSYM stab for statics
+                                       globalsStab.atom                = atom;
+                                       globalsStab.type                = N_STSYM;
+                                       globalsStab.other               = 1;
+                                       globalsStab.desc                = 0;
+                                       globalsStab.value               = 0;
+                                       globalsStab.string              = name;
+                                       state.stabs.push_back(globalsStab);
+                               }
+                               else {
+                                       // Synthesize GSYM stab for other globals
+                                       globalsStab.atom                = atom;
+                                       globalsStab.type                = N_GSYM;
+                                       globalsStab.other               = 1;
+                                       globalsStab.desc                = 0;
+                                       globalsStab.value               = 0;
+                                       globalsStab.string              = name;
+                                       state.stabs.push_back(globalsStab);
+                               }
+                       }
+               }
+       }
+
+       if ( wroteStartSO ) {
+               //  emit ending SO
+               ld::relocatable::File::Stab endFileStab;
+               endFileStab.atom                = NULL;
+               endFileStab.type                = N_SO;
+               endFileStab.other               = 1;
+               endFileStab.desc                = 0;
+               endFileStab.value               = 0;
+               endFileStab.string              = "";
+               state.stabs.push_back(endFileStab);
+       }
+       
+       // copy any stabs from .o file 
+       std::set<const ld::File*> filesSeenWithStabs;
+       for (std::set<const ld::Atom*>::iterator it=atomsWithStabs.begin(); it != atomsWithStabs.end(); it++) {
+               const ld::Atom* atom = *it;
+               objFile = dynamic_cast<const ld::relocatable::File*>(atom->file());
+               if ( objFile != NULL ) {
+                       if ( filesSeenWithStabs.count(objFile) == 0 ) {
+                               filesSeenWithStabs.insert(objFile);
+                               const std::vector<ld::relocatable::File::Stab>* stabs = objFile->stabs();
+                               if ( stabs != NULL ) {
+                                       for(std::vector<ld::relocatable::File::Stab>::const_iterator sit = stabs->begin(); sit != stabs->end(); ++sit) {
+                                               ld::relocatable::File::Stab stab = *sit;
+                                               // ignore stabs associated with atoms that were dead stripped or coalesced away
+                                               if ( (sit->atom != NULL) && (atomsWithStabs.count(sit->atom) == 0) )
+                                                       continue;
+                                               // <rdar://problem/8284718> Value of N_SO stabs should be address of first atom from translation unit
+                                               if ( (stab.type == N_SO) && (stab.string != NULL) && (stab.string[0] != '\0') ) {
+                                                       stab.atom = atom;
+                                               }
+                                               state.stabs.push_back(stab);
+                                       }
+                               }
+                       }
+               }
+       }
+       
+}
+
+
+} // namespace tool 
+} // namespace ld 
+
diff --git a/src/ld/OutputFile.h b/src/ld/OutputFile.h
new file mode 100644 (file)
index 0000000..9b49289
--- /dev/null
@@ -0,0 +1,289 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __OUTPUT_FILE_H__
+#define __OUTPUT_FILE_H__
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/sysctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+#include <mach/mach_time.h>
+#include <mach/vm_statistics.h>
+#include <mach/mach_init.h>
+#include <mach/mach_host.h>
+#include <dlfcn.h>
+#include <mach-o/dyld.h>
+
+#include <vector>
+
+#include "Options.h"
+#include "ld.hpp"
+
+namespace ld {
+namespace tool {
+
+class OutputFile
+{
+public:
+                                                               OutputFile(const Options& opts);
+
+       
+       // iterates all atoms in initial files
+       void                                            write(ld::Internal&);
+       bool                                            findSegment(ld::Internal& state, uint64_t addr, uint64_t* start, uint64_t* end, uint32_t* index);
+       void                                            setLazyBindingInfoOffset(uint64_t lpAddress, uint32_t lpInfoOffset);
+       uint32_t                                        dylibCount();
+       const ld::dylib::File*          dylibByOrdinal(unsigned int ordinal);
+       uint32_t                                        dylibToOrdinal(const ld::dylib::File*);
+       uint32_t                                        encryptedTextStartOffset()      { return _encryptedTEXTstartOffset; }
+       uint32_t                                        encryptedTextEndOffset()        { return _encryptedTEXTendOffset; }
+       int                                                     compressedOrdinalForAtom(const ld::Atom* target);
+       
+       
+       
+       bool                                            hasWeakExternalSymbols;
+       bool                                            usesWeakExternalSymbols;
+       bool                                            overridesWeakExternalSymbols;
+       bool                                            _noReExportedDylibs;
+       bool                                            hasThreadLocalVariableDefinitions;
+       bool                                            pieDisabled;
+       ld::Internal::FinalSection*     headerAndLoadCommandsSection;
+       ld::Internal::FinalSection*     rebaseSection;
+       ld::Internal::FinalSection*     bindingSection;
+       ld::Internal::FinalSection*     weakBindingSection;
+       ld::Internal::FinalSection*     lazyBindingSection;
+       ld::Internal::FinalSection*     exportSection;
+       ld::Internal::FinalSection*     splitSegInfoSection;
+       ld::Internal::FinalSection*     functionStartsSection;
+       ld::Internal::FinalSection*     symbolTableSection;
+       ld::Internal::FinalSection*     stringPoolSection;
+       ld::Internal::FinalSection*     localRelocationsSection;
+       ld::Internal::FinalSection*     externalRelocationsSection;
+       ld::Internal::FinalSection*     sectionRelocationsSection;
+       ld::Internal::FinalSection*     indirectSymbolTableSection;
+       
+       struct RebaseInfo {
+                                               RebaseInfo(uint8_t t, uint64_t addr) : _type(t), _address(addr) {}
+               uint8_t                 _type;
+               uint64_t                _address;
+               // for sorting
+               int operator<(const RebaseInfo& rhs) const {
+                       // sort by type, then address
+                       if ( this->_type != rhs._type )
+                               return  (this->_type < rhs._type );
+                       return  (this->_address < rhs._address );
+               }
+       };
+
+       struct BindingInfo {
+                                               BindingInfo(uint8_t t, int ord, const char* sym, bool weak_import, uint64_t addr, int64_t add) 
+                                                       : _type(t), _flags(weak_import ? BIND_SYMBOL_FLAGS_WEAK_IMPORT : 0 ), _libraryOrdinal(ord), 
+                                                               _symbolName(sym), _address(addr), _addend(add) {}
+                                               BindingInfo(uint8_t t, const char* sym, bool non_weak_definition, uint64_t addr, int64_t add) 
+                                                       : _type(t), _flags(non_weak_definition ? BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION : 0 ), 
+                                                        _libraryOrdinal(0), _symbolName(sym), _address(addr), _addend(add) {}
+               uint8_t                 _type;
+               uint8_t                 _flags;
+               int                             _libraryOrdinal;
+               const char*             _symbolName;
+               uint64_t                _address;
+               int64_t                 _addend;
+               
+               // for sorting
+               int operator<(const BindingInfo& rhs) const {
+                       // sort by library, symbol, type, then address
+                       if ( this->_libraryOrdinal != rhs._libraryOrdinal )
+                               return  (this->_libraryOrdinal < rhs._libraryOrdinal );
+                       if ( this->_symbolName != rhs._symbolName )
+                               return ( strcmp(this->_symbolName, rhs._symbolName) < 0 );
+                       if ( this->_type != rhs._type )
+                               return  (this->_type < rhs._type );
+                       return  (this->_address < rhs._address );
+               }
+       };
+       
+       struct SplitSegInfoEntry {
+                                               SplitSegInfoEntry(uint64_t a, ld::Fixup::Kind k) : address(a), kind(k) {}
+               uint64_t                address;
+               ld::Fixup::Kind kind;
+       };
+       
+private:
+       void                                            buildDylibOrdinalMapping(ld::Internal&);
+       bool                                            hasOrdinalForInstallPath(const char* path, int* ordinal);
+       void                                            addLoadCommands(ld::Internal& state);
+       void                                            addLinkEdit(ld::Internal& state);
+       void                                            addPreloadLinkEdit(ld::Internal& state);
+       void                                            generateLinkEditInfo(ld::Internal& state);
+       void                                            buildSymbolTable(ld::Internal& state);
+       void                                            writeOutputFile(ld::Internal& state);
+       void                                            assignFileOffsets(ld::Internal& state);
+       void                                            setSectionSizesAndAlignments(ld::Internal& state);
+       void                                            addSectionRelocs(ld::Internal& state, ld::Internal::FinalSection* sect,  
+                                                                                               const ld::Atom* atom, ld::Fixup* fixupWithTarget, 
+                                                                                               ld::Fixup* fixupWithMinusTarget, ld::Fixup* fixupWithStore,
+                                                                                               const ld::Atom* target, const ld::Atom* minusTarget, 
+                                                                                               uint64_t targetAddend, uint64_t minusTargetAddend);
+       void                                            addDyldInfo(ld::Internal& state, ld::Internal::FinalSection* sect,  
+                                                                                               const ld::Atom* atom, ld::Fixup* fixupWithTarget,
+                                                                                               ld::Fixup* fixupWithMinusTarget, ld::Fixup* fixupWithStore,
+                                                                                               const ld::Atom* target, const ld::Atom* minusTarget, 
+                                                                                               uint64_t targetAddend, uint64_t minusTargetAddend);
+       void                                            addClassicRelocs(ld::Internal& state, ld::Internal::FinalSection* sect,  
+                                                                                               const ld::Atom* atom, ld::Fixup* fixupWithTarget, 
+                                                                                               ld::Fixup* fixupWithMinusTarget, ld::Fixup* fixupWithStore,
+                                                                                               const ld::Atom* target, const ld::Atom* minusTarget, 
+                                                                                               uint64_t targetAddend, uint64_t minusTargetAddend);
+       bool                                            useExternalSectionReloc(const ld::Atom* atom, const ld::Atom* target, 
+                                                                                                                       ld::Fixup* fixupWithTarget);
+       uint64_t                                        pageAlign(uint64_t addr);
+       uint64_t                                        pageAlign(uint64_t addr, uint64_t pageSize);
+       void                                            setLoadCommandsPadding(ld::Internal& state);
+       void                                            assignAtomAddresses(ld::Internal& state);
+       void                                            addRebaseInfo(const ld::Atom* atom, const ld::Fixup* fixup, const ld::Atom* target);
+       void                                            makeRebasingInfo(ld::Internal& state);
+       void                                            makeBindingInfo(ld::Internal& state);
+       void                                            updateLINKEDITAddresses(ld::Internal& state);
+       void                                            applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::Atom*  atom, uint8_t* buffer);
+       uint64_t                                        addressOf(const ld::Internal& state, const ld::Fixup* fixup, const ld::Atom** target);
+       bool                                            targetIsThumb(ld::Internal& state, const ld::Fixup* fixup);
+       uint32_t                                        lazyBindingInfoOffsetForLazyPointerAddress(uint64_t lpAddress);
+       void                                            copyNoOps(uint8_t* from, uint8_t* to);
+       bool                                            isPointerToTarget(ld::Fixup::Kind kind);
+       bool                                            isPointerFromTarget(ld::Fixup::Kind kind);
+       bool                                            isPcRelStore(ld::Fixup::Kind kind);
+       bool                                            isStore(ld::Fixup::Kind kind);
+       bool                                            storeAddendOnly(const ld::Atom* inAtom, const ld::Atom* target, bool pcRel=false);
+       bool                                            setsTarget(ld::Fixup::Kind kind);
+       void                                            addFixupOutInfo(ld::Internal& state);
+       void                                            makeRelocations(ld::Internal& state);
+       void                                            makeSectionRelocations(ld::Internal& state);
+       void                                            makeDyldInfo(ld::Internal& state);
+       void                                            makeSplitSegInfo(ld::Internal& state);
+       void                                            writeMapFile(ld::Internal& state);
+       uint64_t                                        lookBackAddend(ld::Fixup::iterator fit);
+       bool                                            takesNoDiskSpace(const ld::Section* sect);
+       bool                                            hasZeroForFileOffset(const ld::Section* sect);
+       
+       void                                            printSectionLayout(ld::Internal& state);
+       void                                            rangeCheck8(int64_t delta, ld::Internal& state, const ld::Atom* atom, 
+                                                                                                                                                                                       const ld::Fixup* fixup);
+       void                                            rangeCheck16(int64_t delta, ld::Internal& state, const ld::Atom* atom, 
+                                                                                                                                                                                       const ld::Fixup* fixup);
+       void                                            rangeCheckBranch32(int64_t delta, ld::Internal& state, const ld::Atom* atom, 
+                                                                                                                                                                                       const ld::Fixup* fixup);
+       void                                            rangeCheckRIP32(int64_t delta, ld::Internal& state, const ld::Atom* atom, 
+                                                                                                                                                                                       const ld::Fixup* fixup);
+       void                                            rangeCheckARM12(int64_t delta, ld::Internal& state, const ld::Atom* atom, 
+                                                                                                                                                                                       const ld::Fixup* fixup);
+       void                                            rangeCheckARMBranch24(int64_t delta, ld::Internal& state, const ld::Atom* atom, 
+                                                                                                                                                                                       const ld::Fixup* fixup);
+       void                                            rangeCheckThumbBranch22(int64_t delta, ld::Internal& state, const ld::Atom* atom, 
+                                                                                                                                                                                       const ld::Fixup* fixup);
+       void                                            rangeCheckPPCBranch24(int64_t delta, ld::Internal& state, const ld::Atom* atom, 
+                                                                                                                                                                                       const ld::Fixup* fixup);
+       void                                            rangeCheckPPCBranch14(int64_t delta, ld::Internal& state, const ld::Atom* atom, 
+                                                                                                                                                                                       const ld::Fixup* fixup);
+       uint64_t                                        sectionOffsetOf(const ld::Internal& state, const ld::Fixup* fixup);
+       uint64_t                                        tlvTemplateOffsetOf(const ld::Internal& state, const ld::Fixup* fixup);
+       void                                            dumpAtomsBySection(ld::Internal& state, bool);
+       void                                            synthesizeDebugNotes(ld::Internal& state);
+       const char*                                     assureFullPath(const char* path);
+       void                                            noteTextReloc(const ld::Atom* atom, const ld::Atom* target);
+
+       
+       static uint16_t                         get16LE(uint8_t* loc);
+       static void                                     set16LE(uint8_t* loc, uint16_t value);
+       static uint32_t                         get32LE(uint8_t* loc);
+       static void                                     set32LE(uint8_t* loc, uint32_t value);
+       static uint64_t                         get64LE(uint8_t* loc);
+       static void                                     set64LE(uint8_t* loc, uint64_t value);
+
+       static uint16_t                         get16BE(uint8_t* loc);
+       static void                                     set16BE(uint8_t* loc, uint16_t value);
+       static uint32_t                         get32BE(uint8_t* loc);
+       static void                                     set32BE(uint8_t* loc, uint32_t value);
+       static uint64_t                         get64BE(uint8_t* loc);
+       static void                                     set64BE(uint8_t* loc, uint64_t value);
+
+
+
+       const Options&                                                  _options;
+       std::map<const ld::dylib::File*, int>   _dylibToOrdinal;
+       std::vector<const ld::dylib::File*>             _dylibsToLoad;
+       std::vector<const char*>                                _dylibOrdinalPaths;
+       const bool                                                              _hasDyldInfo;
+       const bool                                                              _hasSymbolTable;
+       const bool                                                              _hasSectionRelocations;
+       const bool                                                              _hasSplitSegInfo;
+       const bool                                                              _hasFunctionStartsInfo;
+                 bool                                                          _hasDynamicSymbolTable;
+                 bool                                                          _hasLocalRelocations;
+                 bool                                                          _hasExternalRelocations;
+       uint64_t                                                                _fileSize;
+       std::map<uint64_t, uint32_t>                    _lazyPointerAddressToInfoOffset;
+       uint32_t                                                                _encryptedTEXTstartOffset;
+       uint32_t                                                                _encryptedTEXTendOffset;
+public:
+       std::vector<const ld::Atom*>                    _localAtoms;
+       std::vector<const ld::Atom*>                    _exportedAtoms;
+       std::vector<const ld::Atom*>                    _importedAtoms;
+       uint32_t                                                                _localSymbolsStartIndex;
+       uint32_t                                                                _localSymbolsCount;
+       uint32_t                                                                _globalSymbolsStartIndex;
+       uint32_t                                                                _globalSymbolsCount;
+       uint32_t                                                                _importSymbolsStartIndex;
+       uint32_t                                                                _importSymbolsCount;
+       std::map<const ld::Atom*, uint32_t>             _atomToSymbolIndex;
+       std::vector<RebaseInfo>                                 _rebaseInfo;
+       std::vector<BindingInfo>                                _bindingInfo;
+       std::vector<BindingInfo>                                _lazyBindingInfo;
+       std::vector<BindingInfo>                                _weakBindingInfo;
+       std::vector<SplitSegInfoEntry>                  _splitSegInfos;
+       class HeaderAndLoadCommandsAbtract*             _headersAndLoadCommandAtom;
+       class RelocationsAtomAbstract*                  _sectionsRelocationsAtom;
+       class RelocationsAtomAbstract*                  _localRelocsAtom;
+       class RelocationsAtomAbstract*                  _externalRelocsAtom;
+       class ClassicLinkEditAtom*                              _symbolTableAtom;
+       class ClassicLinkEditAtom*                              _indirectSymbolTableAtom;
+       class StringPoolAtom*                                   _stringPoolAtom;
+       class LinkEditAtom*                                             _rebasingInfoAtom;
+       class LinkEditAtom*                                             _bindingInfoAtom;
+       class LinkEditAtom*                                             _lazyBindingInfoAtom;
+       class LinkEditAtom*                                             _weakBindingInfoAtom;
+       class LinkEditAtom*                                             _exportInfoAtom;
+       class LinkEditAtom*                                             _splitSegInfoAtom;
+       class LinkEditAtom*                                             _functionStartsAtom;
+};
+
+} // namespace tool 
+} // namespace ld 
+
+#endif // __OUTPUT_FILE_H__
diff --git a/src/ld/Resolver.cpp b/src/ld/Resolver.cpp
new file mode 100644 (file)
index 0000000..e17e632
--- /dev/null
@@ -0,0 +1,1402 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
+ *
+ * Copyright (c) 2009-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/sysctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+#include <mach/mach_time.h>
+#include <mach/vm_statistics.h>
+#include <mach/mach_init.h>
+#include <mach/mach_host.h>
+#include <dlfcn.h>
+#include <mach-o/dyld.h>
+#include <mach-o/fat.h>
+
+#include <string>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+#include <list>
+#include <algorithm>
+#include <ext/hash_map>
+#include <ext/hash_set>
+#include <dlfcn.h>
+#include <AvailabilityMacros.h>
+
+#include "Options.h"
+
+#include "ld.hpp"
+#include "InputFiles.h"
+#include "SymbolTable.h"
+#include "Resolver.h"
+#include "parsers/lto_file.h"
+
+
+namespace ld {
+namespace tool {
+
+
+//
+// An ExportAtom has no content.  It exists so that the linker can track which imported
+// symbols came from which dynamic libraries.
+//
+class UndefinedProxyAtom : public ld::Atom
+{
+public:
+                                                                                       UndefinedProxyAtom(const char* nm)
+                                                                                               : ld::Atom(_s_section, ld::Atom::definitionProxy, 
+                                                                                                       ld::Atom::combineNever, ld::Atom::scopeLinkageUnit, 
+                                                                                                       ld::Atom::typeUnclassified, 
+                                                                                                       ld::Atom::symbolTableIn, false, false, false, ld::Atom::Alignment(0)), 
+                                                                                                       _name(nm) {}
+       // overrides of ld::Atom
+       virtual const ld::File*                                         file() const            { return NULL; }
+       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 0; }
+       virtual uint64_t                                                        objectAddress() const { return 0; }
+       virtual void                                                            copyRawContent(uint8_t buffer[]) const { }
+       virtual void                                                            setScope(Scope)         { }
+
+protected:
+
+       virtual                                                                 ~UndefinedProxyAtom() {}
+
+       const char*                                                             _name;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section UndefinedProxyAtom::_s_section("__TEXT", "__import", ld::Section::typeImportProxies, true);
+
+
+
+
+class AliasAtom : public ld::Atom
+{
+public:
+                                                                               AliasAtom(const ld::Atom& target, const char* nm) : 
+                                                                                       ld::Atom(target.section(), target.definition(), ld::Atom::combineNever,
+                                                                                                       ld::Atom::scopeGlobal, target.contentType(), 
+                                                                                                       target.symbolTableInclusion(), target.dontDeadStrip(), 
+                                                                                                       target.isThumb(), true, target.alignment()),
+                                                                                       _name(nm), 
+                                                                                       _aliasOf(target),
+                                                                                       _fixup(0, ld::Fixup::k1of1, ld::Fixup::kindNoneFollowOn, &target) { }
+
+       // overrides of ld::Atom
+       virtual const ld::File*                         file() const            { return _aliasOf.file(); }
+       virtual bool                                            translationUnitSource(const char** dir, const char** nm) const
+                                                                                                                       { return _aliasOf.translationUnitSource(dir, nm); }
+       virtual const char*                                     name() const            { return _name; }
+       virtual uint64_t                                        size() const            { return 0; }
+       virtual uint64_t                                        objectAddress() const { return _aliasOf.objectAddress(); }
+       virtual void                                            copyRawContent(uint8_t buffer[]) const { }
+       virtual const uint8_t*                          rawContentPointer() const { return NULL; }
+       virtual unsigned long                           contentHash(const class ld::IndirectBindingTable& ibt) const 
+                                                                                                                       { return _aliasOf.contentHash(ibt);  }
+       virtual bool                                            canCoalesceWith(const ld::Atom& rhs, const class ld::IndirectBindingTable& ibt) const 
+                                                                                                                       { return _aliasOf.canCoalesceWith(rhs,ibt); }
+       virtual ld::Fixup::iterator                             fixupsBegin() const     { return (ld::Fixup*)&_fixup; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const   { return &((ld::Fixup*)&_fixup)[1]; }
+       virtual ld::Atom::UnwindInfo::iterator  beginUnwind() const { return  NULL; }
+       virtual ld::Atom::UnwindInfo::iterator  endUnwind() const       { return NULL; }
+       virtual ld::Atom::LineInfo::iterator    beginLineInfo() const { return  NULL; }
+       virtual ld::Atom::LineInfo::iterator    endLineInfo() const { return NULL; }
+                                                                                                                       
+private:
+       const char*                                                     _name;
+       const ld::Atom&                                         _aliasOf;
+       ld::Fixup                                                       _fixup;
+};
+
+
+
+class SectionBoundaryAtom : public ld::Atom
+{
+public:
+       static SectionBoundaryAtom*                     makeSectionBoundaryAtom(const char* name, bool start, const char* segSectName); 
+       static SectionBoundaryAtom*                     makeOldSectionBoundaryAtom(const char* name, bool start);
+       
+       // overrides of ld::Atom
+       virtual bool                                            translationUnitSource(const char** dir, const char** nm) const
+                                                                                                                       { return false; }
+       virtual const ld::File*                         file() const            { return NULL; }
+       virtual const char*                                     name() const            { return _name; }
+       virtual uint64_t                                        size() const            { return 0; }
+       virtual void                                            copyRawContent(uint8_t buffer[]) const { }
+       virtual const uint8_t*                          rawContentPointer() const { return NULL; }
+       virtual uint64_t                                        objectAddress() const { return 0; }
+                                                                                                                       
+private:
+
+                                                                               SectionBoundaryAtom(const char* nm, const ld::Section& sect,
+                                                                                                                       ld::Atom::ContentType cont) : 
+                                                                                       ld::Atom(sect, 
+                                                                                                       ld::Atom::definitionRegular, 
+                                                                                                       ld::Atom::combineNever,
+                                                                                                       ld::Atom::scopeLinkageUnit, 
+                                                                                                       cont, 
+                                                                                                       ld::Atom::symbolTableNotIn,  
+                                                                                                       false, false, true, ld::Atom::Alignment(0)),
+                                                                                       _name(nm) { }
+
+       const char*                                                     _name;
+};
+
+SectionBoundaryAtom* SectionBoundaryAtom::makeSectionBoundaryAtom(const char* name, bool start, const char* segSectName)
+{
+       
+       const char* segSectDividor = strrchr(segSectName, '$');
+       if ( segSectDividor == NULL )
+               throwf("malformed section$ symbol name: %s", name);
+       const char* sectionName = segSectDividor + 1;
+       int segNameLen = segSectDividor - segSectName;
+       if ( segNameLen > 16 )
+               throwf("malformed section$ symbol name: %s", name);
+       char segName[18];
+       strlcpy(segName, segSectName, segNameLen+1);
+       
+       const ld::Section* section = new ld::Section(strdup(segName), sectionName, ld::Section::typeUnclassified);
+       return new SectionBoundaryAtom(name, *section, (start ? ld::Atom::typeSectionStart : typeSectionEnd));
+}
+
+SectionBoundaryAtom* SectionBoundaryAtom::makeOldSectionBoundaryAtom(const char* name, bool start)
+{
+       // e.g. __DATA__bss__begin
+       char segName[18];
+       strlcpy(segName, name, 7);
+       
+       char sectName[18];
+       int nameLen = strlen(name);
+       strlcpy(sectName, &name[6], (start ? nameLen-12 : nameLen-10));
+       warning("grandfathering in old symbol '%s' as alias for 'section$%s$%s$%s'", name, start ? "start" : "end", segName, sectName);
+       const ld::Section* section = new ld::Section(strdup(segName), strdup(sectName), ld::Section::typeUnclassified);
+       return new SectionBoundaryAtom(name, *section, (start ? ld::Atom::typeSectionStart : typeSectionEnd));
+}
+
+
+
+
+class SegmentBoundaryAtom : public ld::Atom
+{
+public:
+       static SegmentBoundaryAtom*                     makeSegmentBoundaryAtom(const char* name, bool start, const char* segName); 
+       static SegmentBoundaryAtom*                     makeOldSegmentBoundaryAtom(const char* name, bool start); 
+       
+       // overrides of ld::Atom
+       virtual bool                                            translationUnitSource(const char** dir, const char** nm) const
+                                                                                                                       { return false; }
+       virtual const ld::File*                         file() const            { return NULL; }
+       virtual const char*                                     name() const            { return _name; }
+       virtual uint64_t                                        size() const            { return 0; }
+       virtual void                                            copyRawContent(uint8_t buffer[]) const { }
+       virtual const uint8_t*                          rawContentPointer() const { return NULL; }
+       virtual uint64_t                                        objectAddress() const { return 0; }
+                                                                                                                       
+private:
+
+                                                                               SegmentBoundaryAtom(const char* nm, const ld::Section& sect,
+                                                                                                                       ld::Atom::ContentType cont) : 
+                                                                                       ld::Atom(sect, 
+                                                                                                       ld::Atom::definitionRegular, 
+                                                                                                       ld::Atom::combineNever,
+                                                                                                       ld::Atom::scopeLinkageUnit, 
+                                                                                                       cont, 
+                                                                                                       ld::Atom::symbolTableNotIn,  
+                                                                                                       false, false, true, ld::Atom::Alignment(0)),
+                                                                                       _name(nm) { }
+
+       const char*                                                     _name;
+};
+
+SegmentBoundaryAtom* SegmentBoundaryAtom::makeSegmentBoundaryAtom(const char* name, bool start, const char* segName)
+{
+       if ( *segName == '\0' )
+               throwf("malformed segment$ symbol name: %s", name);
+       if ( strlen(segName) > 16 )
+               throwf("malformed segment$ symbol name: %s", name);
+       
+       if ( start ) {
+               const ld::Section* section = new ld::Section(segName, "__start", ld::Section::typeFirstSection, true);
+               return new SegmentBoundaryAtom(name, *section, ld::Atom::typeSectionStart);
+       }
+       else {
+               const ld::Section* section = new ld::Section(segName, "__end", ld::Section::typeLastSection, true);
+               return new SegmentBoundaryAtom(name, *section, ld::Atom::typeSectionEnd);
+       }
+}
+
+SegmentBoundaryAtom* SegmentBoundaryAtom::makeOldSegmentBoundaryAtom(const char* name, bool start)
+{
+       // e.g. __DATA__begin
+       char temp[18];
+       strlcpy(temp, name, 7);
+       char* segName = strdup(temp);
+       
+       warning("grandfathering in old symbol '%s' as alias for 'segment$%s$%s'", name, start ? "start" : "end", segName);
+
+       if ( start ) {
+               const ld::Section* section = new ld::Section(segName, "__start", ld::Section::typeFirstSection, true);
+               return new SegmentBoundaryAtom(name, *section, ld::Atom::typeSectionStart);
+       }
+       else {
+               const ld::Section* section = new ld::Section(segName, "__end", ld::Section::typeLastSection, true);
+               return new SegmentBoundaryAtom(name, *section, ld::Atom::typeSectionEnd);
+       }
+}
+
+void Resolver::initializeState()
+{
+       // set initial objc constraint based on command line options
+       if ( _options.objcGc() )
+               _internal.objcObjectConstraint = ld::File::objcConstraintRetainReleaseOrGC;
+       else if ( _options.objcGcOnly() )
+               _internal.objcObjectConstraint = ld::File::objcConstraintGC;
+       
+       _internal.cpuSubType = _options.subArchitecture();
+}
+
+void Resolver::buildAtomList()
+{
+       // each input files contributes initial atoms
+       _atoms.reserve(1024);
+       _inputFiles.forEachInitialAtom(*this);
+       _completedInitialObjectFiles = true;
+       
+       //_symbolTable.printStatistics();
+}
+
+unsigned int Resolver::ppcSubTypeIndex(uint32_t subtype)
+{
+       switch ( subtype ) {
+               case CPU_SUBTYPE_POWERPC_ALL:
+                       return 0;
+               case CPU_SUBTYPE_POWERPC_750:
+                       // G3
+                       return 1;
+               case CPU_SUBTYPE_POWERPC_7400:
+               case CPU_SUBTYPE_POWERPC_7450:
+                       // G4
+                       return 2;
+               case CPU_SUBTYPE_POWERPC_970:
+                       // G5 can run everything
+                       return 3;
+               default:
+                       throw "Unhandled PPC cpu subtype!";
+                       break;
+       }
+}
+
+void Resolver::doFile(const ld::File& file)
+{
+       const ld::relocatable::File* objFile = dynamic_cast<const ld::relocatable::File*>(&file);
+       const ld::dylib::File* dylibFile = dynamic_cast<const ld::dylib::File*>(&file);
+
+       if ( objFile != NULL ) {
+               // update which form of ObjC is being used
+               switch ( file.objCConstraint() ) {
+                       case ld::File::objcConstraintNone:
+                               break;
+                       case ld::File::objcConstraintRetainRelease:
+                               if ( _internal.objcObjectConstraint == ld::File::objcConstraintGC )
+                                       throwf("%s built with incompatible Garbage Collection settings to link with previous .o files", file.path());
+                               if ( _options.objcGcOnly() )
+                                       throwf("command line specified -objc_gc_only, but file is retain/release based: %s", file.path());
+                               if ( _options.objcGc() )
+                                       throwf("command line specified -objc_gc, but file is retain/release based: %s", file.path());
+                               _internal.objcObjectConstraint = ld::File::objcConstraintRetainRelease;
+                               break;
+                       case ld::File::objcConstraintRetainReleaseOrGC:
+                               if ( _internal.objcObjectConstraint == ld::File::objcConstraintNone )
+                                       _internal.objcObjectConstraint = ld::File::objcConstraintRetainReleaseOrGC;
+                               break;
+                       case ld::File::objcConstraintGC:
+                               if ( _internal.objcObjectConstraint == ld::File::objcConstraintRetainRelease )
+                                       throwf("%s built with incompatible Garbage Collection settings to link with previous .o files", file.path());
+                               _internal.objcObjectConstraint = ld::File::objcConstraintGC;
+                               break;
+               }
+       
+               // in -r mode, if any .o files have dwarf then add UUID to output .o 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;
+       
+               // update cpu-sub-type
+               cpu_subtype_t nextObjectSubType = file.cpuSubType();
+               switch ( _options.architecture() ) {
+                       case CPU_TYPE_POWERPC:
+                               // no checking when -force_cpusubtype_ALL is used
+                               if ( _options.forceCpuSubtypeAll() )
+                                       return;
+                               if ( _options.preferSubArchitecture() ) {
+                                       // warn if some .o file is not compatible with desired output sub-type
+                                       if ( _options.subArchitecture() != nextObjectSubType ) {
+                                               if ( ppcSubTypeIndex(nextObjectSubType) > ppcSubTypeIndex(_options.subArchitecture()) ) {
+                                                       if ( !_inputFiles.inferredArch() )
+                                                               warning("cpu-sub-type of %s is not compatible with command line cpu-sub-type", file.path());
+                                                       _internal.cpuSubType = nextObjectSubType;
+                                               }
+                                       }
+                               }
+                               else {
+                                       // command line to linker just had -arch ppc
+                                       // figure out final sub-type based on sub-type of all .o files
+                                       if ( ppcSubTypeIndex(nextObjectSubType) > ppcSubTypeIndex(_internal.cpuSubType) ) {
+                                               _internal.cpuSubType = nextObjectSubType;
+                                       }
+                               }
+                               break;
+                       
+                       case CPU_TYPE_ARM:
+                               if ( _options.subArchitecture() != nextObjectSubType ) {
+                                       if ( (_options.subArchitecture() == CPU_SUBTYPE_ARM_ALL) && _options.forceCpuSubtypeAll() ) {
+                                               // hack to support gcc multillib build that tries to make sub-type-all slice
+                                       }
+                                       else if ( nextObjectSubType == CPU_SUBTYPE_ARM_ALL ) {
+                                               warning("CPU_SUBTYPE_ARM_ALL subtype is deprecated: %s", file.path());
+                                       }
+                                       else {
+                                               throwf("object file %s was built for different arm sub-type (%d) than link command line (%d)", 
+                                                       file.path(), nextObjectSubType, _options.subArchitecture());
+                                       }
+                               }
+                               break;
+                       
+                       case CPU_TYPE_POWERPC64:
+                               break;
+                               
+                       case CPU_TYPE_I386:
+                               _internal.cpuSubType = CPU_SUBTYPE_I386_ALL;
+                               break;
+                               
+                       case CPU_TYPE_X86_64:
+                               _internal.cpuSubType = CPU_SUBTYPE_X86_64_ALL;
+                               break;
+               }
+       }
+       if ( dylibFile != NULL ) {
+               // update which form of ObjC dylibs are being linked
+               switch ( dylibFile->objCConstraint() ) {
+                       case ld::File::objcConstraintNone:
+                               break;
+                       case ld::File::objcConstraintRetainRelease:
+                               if ( _internal.objcDylibConstraint == ld::File::objcConstraintGC )
+                                       throwf("%s built with incompatible Garbage Collection settings to link with previous dylibs", file.path());
+                               if ( _options.objcGcOnly() )
+                                       throwf("command line specified -objc_gc_only, but dylib is retain/release based: %s", file.path());
+                               if ( _options.objcGc() )
+                                       throwf("command line specified -objc_gc, but dylib is retain/release based: %s", file.path());
+                               _internal.objcDylibConstraint = ld::File::objcConstraintRetainRelease;
+                               break;
+                       case ld::File::objcConstraintRetainReleaseOrGC:
+                               if ( _internal.objcDylibConstraint == ld::File::objcConstraintNone )
+                                       _internal.objcDylibConstraint = ld::File::objcConstraintRetainReleaseOrGC;
+                               break;
+                       case ld::File::objcConstraintGC:
+                               if ( _internal.objcDylibConstraint == ld::File::objcConstraintRetainRelease )
+                                       throwf("%s built with incompatible Garbage Collection settings to link with previous dylibs", file.path());
+                               _internal.objcDylibConstraint = ld::File::objcConstraintGC;
+                               break;
+               }
+       }
+
+}
+
+void Resolver::doAtom(const ld::Atom& atom)
+{
+       //fprintf(stderr, "Resolver::doAtom(%p), name=%s, sect=%s\n", &atom, atom.name(), atom.section().sectionName());
+
+       // add to list of known atoms
+       _atoms.push_back(&atom);
+       
+       // adjust scope
+       if ( _options.hasExportRestrictList() || _options.hasReExportList() ) {
+               const char* name = atom.name();
+               switch ( atom.scope() ) {
+                       case ld::Atom::scopeTranslationUnit:
+                               break;
+                       case ld::Atom::scopeLinkageUnit:
+                               if ( _options.hasExportMaskList() && _options.shouldExport(name) ) {
+                                       // <rdar://problem/5062685> ld does not report error when -r is used and exported symbols are not defined.
+                                       if ( _options.outputKind() == Options::kObjectFile ) 
+                                               throwf("cannot export hidden symbol %s", name);
+                                       // .objc_class_name_* symbols are special 
+                                       if ( atom.section().type() != ld::Section::typeObjC1Classes ) {
+                                               if ( atom.definition() == ld::Atom::definitionProxy ) {
+                                                       // .exp file says to export a symbol, but that symbol is in some dylib being linked
+                                                       if ( _options.canReExportSymbols() ) {
+                                                               // marking proxy atom as global triggers the re-export
+                                                               (const_cast<ld::Atom*>(&atom))->setScope(ld::Atom::scopeGlobal);
+                                                       }
+                                                       else {
+                                                               if ( atom.file() != NULL )
+                                                                       warning("cannot re-export symbol %s from %s\n", SymbolTable::demangle(name), atom.file()->path());
+                                                               else
+                                                                       warning("cannot re-export symbol %s\n", SymbolTable::demangle(name));
+                                                       }
+                                               }
+                                               else {
+                                                       if ( atom.file() != NULL )
+                                                               warning("cannot export hidden symbol %s from %s", SymbolTable::demangle(name), atom.file()->path());
+                                                       else
+                                                               warning("cannot export hidden symbol %s", SymbolTable::demangle(name));
+                                               }
+                                       }
+                               }
+                               else if ( _options.shouldReExport(name) && _options.canReExportSymbols() ) {
+                                       if ( atom.definition() == ld::Atom::definitionProxy ) {
+                                               // marking proxy atom as global triggers the re-export
+                                               (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());
+                                       }
+                               }
+                               break;
+                       case ld::Atom::scopeGlobal:
+                               // check for globals that are downgraded to hidden
+                               if ( ! _options.shouldExport(name) ) {
+                                       (const_cast<ld::Atom*>(&atom))->setScope(ld::Atom::scopeLinkageUnit);
+                                       //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());
+                               }
+                               break;
+               }
+       }
+
+       // work around for kernel that uses 'l' labels in assembly code
+       if ( (atom.symbolTableInclusion() == ld::Atom::symbolTableNotInFinalLinkedImages) 
+                       && (atom.name()[0] == 'l') && (_options.outputKind() == Options::kStaticExecutable) )
+               (const_cast<ld::Atom*>(&atom))->setSymbolTableInclusion(ld::Atom::symbolTableIn);
+
+
+       // tell symbol table about non-static atoms
+       if ( atom.scope() != ld::Atom::scopeTranslationUnit ) {
+               _symbolTable.add(atom, _options.deadCodeStrip() && _completedInitialObjectFiles);
+               
+               // add symbol aliases defined on the command line
+               if ( _options.haveCmdLineAliases() ) {
+                       const std::vector<Options::AliasPair>& aliases = _options.cmdLineAliases();
+                       for (std::vector<Options::AliasPair>::const_iterator it=aliases.begin(); it != aliases.end(); ++it) {
+                               if ( strcmp(it->realName, atom.name()) == 0 ) {
+                                       const ld::Atom* alias = new AliasAtom(atom, it->alias);
+                                       this->doAtom(*alias);
+                               }
+                       }
+               }
+       }
+
+       // convert references by-name or by-content to by-slot
+       this->convertReferencesToIndirect(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() )
+                       _deadStripRoots.insert(&atom);
+                       
+               if ( atom.scope() == ld::Atom::scopeGlobal ) {
+                       // <rdar://problem/5524973> -exported_symbols_list that has wildcards and -dead_strip
+                       // in dylibs, every global atom in initial .o files is a root
+                       if ( _options.hasWildCardExportRestrictList() || _options.allGlobalsAreDeadStripRoots() ) {
+                               if ( _options.shouldExport(atom.name()) )
+                                       _deadStripRoots.insert(&atom);
+                       }
+               }
+       }
+}
+
+bool Resolver::isDtraceProbe(ld::Fixup::Kind kind)
+{
+       switch (kind) {
+               case ld::Fixup::kindStoreX86DtraceCallSiteNop:
+               case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
+               case ld::Fixup::kindStoreARMDtraceCallSiteNop:
+               case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear:
+               case ld::Fixup::kindStoreThumbDtraceCallSiteNop:
+               case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
+               case ld::Fixup::kindStorePPCDtraceCallSiteNop:
+               case ld::Fixup::kindStorePPCDtraceIsEnableSiteClear:
+               case ld::Fixup::kindDtraceExtra:
+                       return true;
+               default: 
+                       break;
+       }
+       return false;
+}
+
+void Resolver::convertReferencesToIndirect(const ld::Atom& atom)
+{
+       // convert references by-name or by-content to by-slot
+       SymbolTable::IndirectBindingSlot slot;
+       const ld::Atom* dummy;
+       ld::Fixup::iterator end = atom.fixupsEnd();
+       for (ld::Fixup::iterator fit=atom.fixupsBegin(); fit != end; ++fit) {
+               switch ( fit->binding ) { 
+                       case ld::Fixup::bindingByNameUnbound:
+                               if ( isDtraceProbe(fit->kind) && (_options.outputKind() != Options::kObjectFile ) ) {
+                                       // in final linked images, remove reference
+                                       fit->binding = ld::Fixup::bindingNone;
+                               }
+                               else {
+                                       slot = _symbolTable.findSlotForName(fit->u.name);
+                                       fit->binding = ld::Fixup::bindingsIndirectlyBound;
+                                       fit->u.bindingIndex = slot;
+                               }
+                               break;
+                       case ld::Fixup::bindingByContentBound:
+                               switch ( fit->u.target->combine() ) {
+                                       case ld::Atom::combineNever:
+                                       case ld::Atom::combineByName:
+                                               assert(0 && "wrong combine type for bind by content");
+                                               break;
+                                       case ld::Atom::combineByNameAndContent:
+                                               slot = _symbolTable.findSlotForContent(fit->u.target, &dummy);
+                                               fit->binding = ld::Fixup::bindingsIndirectlyBound;
+                                               fit->u.bindingIndex = slot;
+                                               break;
+                                       case ld::Atom::combineByNameAndReferences:
+                                               slot = _symbolTable.findSlotForReferences(fit->u.target, &dummy);
+                                               fit->binding = ld::Fixup::bindingsIndirectlyBound;
+                                               fit->u.bindingIndex = slot;
+                                               break;
+                               }
+                               break;
+                       case ld::Fixup::bindingNone:
+                       case ld::Fixup::bindingDirectlyBound:
+                       case ld::Fixup::bindingsIndirectlyBound:
+                               break;
+               }
+       }
+}
+
+
+void Resolver::addInitialUndefines()
+{
+       // add initial undefines from -u option
+       for (Options::UndefinesIterator it=_options.initialUndefinesBegin(); it != _options.initialUndefinesEnd(); ++it) {
+               _symbolTable.findSlotForName(*it);
+       }
+}
+
+void Resolver::resolveUndefines()
+{
+       // keep looping until no more undefines were added in last loop
+       unsigned int undefineGenCount = 0xFFFFFFFF;
+       while ( undefineGenCount != _symbolTable.updateCount() ) {
+               undefineGenCount = _symbolTable.updateCount();
+               std::vector<const char*> undefineNames;
+               _symbolTable.undefines(undefineNames);
+               for(std::vector<const char*>::iterator it = undefineNames.begin(); it != undefineNames.end(); ++it) {
+                       const char* undef = *it;
+                       // load for previous undefine may also have loaded this undefine, so check again
+                       if ( ! _symbolTable.hasName(undef) ) {
+                               _inputFiles.searchLibraries(undef, true, true, *this);
+                               if ( !_symbolTable.hasName(undef) && (_options.outputKind() != Options::kObjectFile) ) {
+                                       if ( strncmp(undef, "section$", 8) == 0 ) {
+                                               if ( strncmp(undef, "section$start$", 14) == 0 ) {
+                                                       this->doAtom(*SectionBoundaryAtom::makeSectionBoundaryAtom(undef, true, &undef[14])); 
+                                               }
+                                               else if ( strncmp(undef, "section$end$", 12) == 0 ) {
+                                                       this->doAtom(*SectionBoundaryAtom::makeSectionBoundaryAtom(undef, false, &undef[12])); 
+                                               }
+                                       }
+                                       else if ( strncmp(undef, "segment$", 8) == 0 ) {
+                                               if ( strncmp(undef, "segment$start$", 14) == 0 ) {
+                                                       this->doAtom(*SegmentBoundaryAtom::makeSegmentBoundaryAtom(undef, true, &undef[14])); 
+                                               }
+                                               else if ( strncmp(undef, "segment$end$", 12) == 0 ) {
+                                                       this->doAtom(*SegmentBoundaryAtom::makeSegmentBoundaryAtom(undef, false, &undef[12])); 
+                                               }
+                                       }
+                                       else if ( _options.outputKind() == Options::kPreload ) {
+                                               // for iBoot grandfather in old style section labels
+                                               int undefLen = strlen(undef);
+                                               if ( strcmp(&undef[undefLen-7], "__begin") == 0 ) {
+                                                       if ( undefLen > 13 )
+                                                               this->doAtom(*SectionBoundaryAtom::makeOldSectionBoundaryAtom(undef, true));
+                                                       else
+                                                               this->doAtom(*SegmentBoundaryAtom::makeOldSegmentBoundaryAtom(undef, true));
+                                               }
+                                               else if ( strcmp(&undef[undefLen-5], "__end") == 0 ) {
+                                                       if ( undefLen > 11 )
+                                                               this->doAtom(*SectionBoundaryAtom::makeOldSectionBoundaryAtom(undef, false));
+                                                       else
+                                                               this->doAtom(*SegmentBoundaryAtom::makeOldSegmentBoundaryAtom(undef, false));
+                                               }
+                                       }
+                               }
+                       }
+               }
+               // <rdar://problem/5894163> need to search archives for overrides of common symbols 
+               if ( _symbolTable.hasExternalTentativeDefinitions() ) {
+                       bool searchDylibs = (_options.commonsMode() == Options::kCommonsOverriddenByDylibs);
+                       std::vector<const char*> tents;
+                       _symbolTable.tentativeDefs(tents);
+                       for(std::vector<const char*>::iterator it = tents.begin(); it != tents.end(); ++it) {
+                               // load for previous tentative may also have loaded this tentative, so check again
+                               const ld::Atom* curAtom = _symbolTable.atomForSlot(_symbolTable.findSlotForName(*it));
+                               assert(curAtom != NULL);
+                               if ( curAtom->definition() == ld::Atom::definitionTentative ) {
+                                       _inputFiles.searchLibraries(*it, searchDylibs, true, *this);
+                               }
+                       }
+               }
+       }
+               
+       // create proxies as needed for undefined symbols
+       if ( (_options.undefinedTreatment() != Options::kUndefinedError) || (_options.outputKind() == Options::kObjectFile) ) {
+               std::vector<const char*> undefineNames;
+               _symbolTable.undefines(undefineNames);
+               for(std::vector<const char*>::iterator it = undefineNames.begin(); it != undefineNames.end(); ++it) {
+                       // make proxy
+                       this->doAtom(*new UndefinedProxyAtom(*it));
+               }
+       }
+       
+       // support -U option
+       if ( _options.someAllowedUndefines() ) {
+               std::vector<const char*> undefineNames;
+               _symbolTable.undefines(undefineNames);
+               for(std::vector<const char*>::iterator it = undefineNames.begin(); it != undefineNames.end(); ++it) {
+                       if ( _options.allowedUndefined(*it) ) {
+                               // make proxy
+                               this->doAtom(*new UndefinedProxyAtom(*it));
+                       }
+               }
+       }
+       
+}
+
+
+void Resolver::markLive(const ld::Atom& atom, WhyLiveBackChain* previous)
+{
+       //fprintf(stderr, "markLive(%p) %s\n", &atom, atom.name());
+       // if -why_live cares about this symbol, then dump chain
+       if ( (previous->referer != NULL) && _options.printWhyLive(atom.name()) ) {
+               fprintf(stderr, "%s from %s\n", atom.name(), atom.file()->path());
+               int depth = 1;
+               for(WhyLiveBackChain* p = previous; p != NULL; p = p->previous, ++depth) {
+                       for(int i=depth; i > 0; --i)
+                               fprintf(stderr, "  ");
+                       fprintf(stderr, "%s from %s\n", p->referer->name(), p->referer->file()->path());
+               }
+       }
+       
+       // if already marked live, then done (stop recursion)
+       if ( atom.live() )
+               return;
+               
+       // mark this atom is live
+       (const_cast<ld::Atom*>(&atom))->setLive();
+       
+       // mark all atoms it references as live
+       WhyLiveBackChain thisChain;
+       thisChain.previous = previous;
+       thisChain.referer = &atom;
+       for (ld::Fixup::iterator fit = atom.fixupsBegin(), end=atom.fixupsEnd(); fit != end; ++fit) {
+               const ld::Atom* target;
+               switch ( fit->kind ) {
+                       case ld::Fixup::kindNone:
+                       case ld::Fixup::kindNoneFollowOn:
+                       case ld::Fixup::kindNoneGroupSubordinate:
+                       case ld::Fixup::kindNoneGroupSubordinateFDE:
+                       case ld::Fixup::kindNoneGroupSubordinateLSDA:
+                       case ld::Fixup::kindSetTargetAddress:
+                       case ld::Fixup::kindSubtractTargetAddress:
+                       case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+                       case ld::Fixup::kindStoreTargetAddressLittleEndian64:
+                       case ld::Fixup::kindStoreTargetAddressBigEndian32:
+                       case ld::Fixup::kindStoreTargetAddressBigEndian64:
+                       case ld::Fixup::kindStoreTargetAddressX86PCRel32:
+                       case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
+                       case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
+                       case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
+                       case ld::Fixup::kindStoreTargetAddressARMBranch24:
+                       case ld::Fixup::kindStoreTargetAddressThumbBranch22:
+                       case ld::Fixup::kindStoreTargetAddressPPCBranch24:
+                               if ( fit->binding == ld::Fixup::bindingByContentBound ) {
+                                       // normally this was done in convertReferencesToIndirect()
+                                       // but a archive loaded .o file may have a forward reference
+                                       SymbolTable::IndirectBindingSlot slot;
+                                       const ld::Atom* dummy;
+                                       switch ( fit->u.target->combine() ) {
+                                               case ld::Atom::combineNever:
+                                               case ld::Atom::combineByName:
+                                                       assert(0 && "wrong combine type for bind by content");
+                                                       break;
+                                               case ld::Atom::combineByNameAndContent:
+                                                       slot = _symbolTable.findSlotForContent(fit->u.target, &dummy);
+                                                       fit->binding = ld::Fixup::bindingsIndirectlyBound;
+                                                       fit->u.bindingIndex = slot;
+                                                       break;
+                                               case ld::Atom::combineByNameAndReferences:
+                                                       slot = _symbolTable.findSlotForReferences(fit->u.target, &dummy);
+                                                       fit->binding = ld::Fixup::bindingsIndirectlyBound;
+                                                       fit->u.bindingIndex = slot;
+                                                       break;
+                                       }
+                               }
+                               switch ( fit->binding ) {
+                                       case ld::Fixup::bindingDirectlyBound:
+                                               markLive(*(fit->u.target), &thisChain);
+                                               break;
+                                       case ld::Fixup::bindingByNameUnbound:
+                                               // doAtom() did not convert to indirect in dead-strip mode, so that now
+                                               fit->u.bindingIndex = _symbolTable.findSlotForName(fit->u.name);
+                                               fit->binding = ld::Fixup::bindingsIndirectlyBound;
+                                               // fall into next case
+                                       case ld::Fixup::bindingsIndirectlyBound:
+                                               target = _internal.indirectBindingTable[fit->u.bindingIndex];
+                                               if ( target == NULL ) {
+                                                       const char* targetName = _symbolTable.indirectName(fit->u.bindingIndex);
+                                                       _inputFiles.searchLibraries(targetName, true, true, *this);
+                                                       target = _internal.indirectBindingTable[fit->u.bindingIndex];
+                                               }
+                                               if ( target != NULL ) {
+                                                       if ( target->definition() == ld::Atom::definitionTentative ) {
+                                                               // <rdar://problem/5894163> need to search archives for overrides of common symbols 
+                                                               bool searchDylibs = (_options.commonsMode() == Options::kCommonsOverriddenByDylibs);
+                                                               _inputFiles.searchLibraries(target->name(), searchDylibs, true, *this);
+                                                               // recompute target since it may have been overridden by searchLibraries()
+                                                               target = _internal.indirectBindingTable[fit->u.bindingIndex];
+                                                       }
+                                                       this->markLive(*target, &thisChain);
+                                               }
+                                               else {
+                                                       _atomsWithUnresolvedReferences.push_back(&atom);
+                                               }
+                                               break;
+                                       default:
+                                               assert(0 && "bad binding during dead stripping");
+                               }
+                               break;
+            default:
+                break;    
+               }
+       }
+
+}
+
+
+void Resolver::deadStripOptimize()
+{
+       // only do this optimization with -dead_strip
+       if ( ! _options.deadCodeStrip() ) 
+               return;
+               
+       // add entry point (main) to live roots
+       const ld::Atom* entry = this->entryPoint(true);
+       if ( entry != NULL )
+               _deadStripRoots.insert(entry);
+               
+       // add -exported_symbols_list, -init, and -u entries to live roots
+       for (Options::UndefinesIterator uit=_options.initialUndefinesBegin(); uit != _options.initialUndefinesEnd(); ++uit) {
+               SymbolTable::IndirectBindingSlot slot = _symbolTable.findSlotForName(*uit);
+               if ( _internal.indirectBindingTable[slot] == NULL ) {
+                       _inputFiles.searchLibraries(*uit, false, true, *this);
+               }
+               if ( _internal.indirectBindingTable[slot] != NULL )
+                       _deadStripRoots.insert(_internal.indirectBindingTable[slot]);
+       }
+       
+       // this helper is only referenced by synthesize stubs, assume it will be used
+       if ( _internal.classicBindingHelper != NULL ) 
+               _deadStripRoots.insert(_internal.classicBindingHelper);
+
+       // this helper is only referenced by synthesize stubs, assume it will be used
+       if ( _internal.compressedFastBinderProxy != NULL ) 
+               _deadStripRoots.insert(_internal.compressedFastBinderProxy);
+
+       // this helper is only referenced by synthesized lazy stubs, assume it will be used
+       if ( _internal.lazyBindingHelper != NULL )
+               _deadStripRoots.insert(_internal.lazyBindingHelper);
+
+       // add all dont-dead-strip atoms as roots
+       for (std::vector<const ld::Atom*>::const_iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
+               const ld::Atom* atom = *it;
+               if ( atom->dontDeadStrip() ) {
+                       //fprintf(stderr, "dont dead strip: %p %s %s\n", atom, atom->section().sectionName(), atom->name());
+                       _deadStripRoots.insert(atom);
+                       // unset liveness, so markLive() will recurse
+                       (const_cast<ld::Atom*>(atom))->setLive(0);
+               }
+       }
+       
+       // mark all roots as live, and all atoms they reference
+       for (std::set<const ld::Atom*>::iterator it=_deadStripRoots.begin(); it != _deadStripRoots.end(); ++it) {
+               WhyLiveBackChain rootChain;
+               rootChain.previous = NULL;
+               rootChain.referer = *it;
+               this->markLive(**it, &rootChain);
+       }
+       
+       // now remove all non-live atoms from _atoms
+       const bool log = false;
+       if ( log ) {
+               fprintf(stderr, "deadStripOptimize() all atoms with liveness:\n");
+               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());
+               }
+       }
+       _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), NotLive()), _atoms.end());
+}
+
+
+void Resolver::liveUndefines(std::vector<const char*>& undefs)
+{
+       StringSet  undefSet;
+       // search all live 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;
+               assert(atom->live());
+               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) {
+               undefs.push_back(*it);
+       }
+}
+
+
+
+// <rdar://problem/8252819> warn when .objc_class_name_* symbol missing
+class ExportedObjcClass
+{
+public:
+       ExportedObjcClass(const Options& opt) : _options(opt)  {}
+
+       bool operator()(const char* name) const {
+               if ( (strncmp(name, ".objc_class_name_", 17) == 0) && _options.shouldExport(name) ) {
+                       warning("ignoring undefined symbol %s from -exported_symbols_list", name);
+                       return true;
+               }
+               const char* s = strstr(name, "CLASS_$_");
+               if ( s != NULL ) {
+                       char temp[strlen(name)+16];
+                       strcpy(temp, ".objc_class_name_");
+                       strcat(temp, &s[8]);
+                       if ( _options.wasRemovedExport(temp) ) {
+                               warning("ignoring undefined symbol %s from -exported_symbols_list", temp);
+                               return true;
+                       }
+               }
+               return false;
+       }
+private:
+       const Options& _options;
+};
+
+
+// temp hack for undefined aliases
+class UndefinedAlias
+{
+public:
+       UndefinedAlias(const Options& opt) : _aliases(opt.cmdLineAliases()) {}
+
+       bool operator()(const char* name) const {
+               for (std::vector<Options::AliasPair>::const_iterator it=_aliases.begin(); it != _aliases.end(); ++it) {
+                       if ( strcmp(it->realName, name) == 0 ) {
+                               warning("undefined base symbol '%s' for alias '%s'", name, it->alias);
+                               return true;
+                       }
+               }
+               return false;
+       }
+private:
+       const std::vector<Options::AliasPair>&  _aliases;
+};
+
+
+
+static const char* pathLeafName(const char* path)
+{
+       const char* shortPath = strrchr(path, '/');
+       if ( shortPath == NULL )
+               return path;
+       else
+               return &shortPath[1];
+}
+
+bool Resolver::printReferencedBy(const char* name, SymbolTable::IndirectBindingSlot slot)
+{
+       unsigned foundReferenceCount = 0;
+       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) {
+                       if ( fit->binding == ld::Fixup::bindingsIndirectlyBound ) {
+                               if ( fit->u.bindingIndex == slot ) {
+                                       if ( atom->contentType() == ld::Atom::typeNonLazyPointer ) {
+                                               const ld::Atom* existingAtom;
+                                               unsigned int nlSlot = _symbolTable.findSlotForReferences(atom, &existingAtom);
+                                               if ( printReferencedBy(name, nlSlot) )
+                                                       ++foundReferenceCount;
+                                       }
+                                       else if ( atom->contentType() == ld::Atom::typeCFI ) {
+                                               fprintf(stderr, "      Dwarf Exception Unwind Info (__eh_frame) in %s\n", pathLeafName(atom->file()->path()));
+                                               ++foundReferenceCount;
+                                       }
+                                       else {
+                                               fprintf(stderr, "      %s in %s\n", SymbolTable::demangle(atom->name()), pathLeafName(atom->file()->path()));
+                                               ++foundReferenceCount;
+                                               break; // if undefined used twice in a function, only show first
+                                       }
+                               }
+                       }
+               }
+               if ( foundReferenceCount > 6 ) {
+                       fprintf(stderr, "      ...\n");
+                       break; // only show first six uses of undefined symbol
+               }
+       }
+       return (foundReferenceCount != 0);
+}
+
+void Resolver::checkUndefines(bool force)
+{
+       // when using LTO, undefines are checked after bitcode is optimized
+       if ( _haveLLVMObjs && !force )
+               return;
+
+       // error out on any remaining undefines
+       bool doPrint = true;
+       bool doError = true;
+       switch ( _options.undefinedTreatment() ) {
+               case Options::kUndefinedError:
+                       break;
+               case Options::kUndefinedDynamicLookup:
+                       doError = false;
+                       break;
+               case Options::kUndefinedWarning:
+                       doError = false;
+                       break;
+               case Options::kUndefinedSuppress:
+                       doError = false;
+                       doPrint = false;
+                       break;
+       }
+       std::vector<const char*> unresolvableUndefines;
+       if ( _options.deadCodeStrip() ) 
+               this->liveUndefines(unresolvableUndefines);
+       else    
+               _symbolTable.undefines(unresolvableUndefines);
+
+       // <rdar://problem/8252819> assert when .objc_class_name_* symbol missing
+       if ( _options.hasExportMaskList() ) {
+               unresolvableUndefines.erase(std::remove_if(unresolvableUndefines.begin(), unresolvableUndefines.end(), ExportedObjcClass(_options)), unresolvableUndefines.end());
+       }
+
+       // hack to temporarily make missing aliases a warning
+       if ( _options.haveCmdLineAliases() ) {
+               unresolvableUndefines.erase(std::remove_if(unresolvableUndefines.begin(), unresolvableUndefines.end(), UndefinedAlias(_options)), unresolvableUndefines.end());
+       }
+       
+       const int unresolvableCount = unresolvableUndefines.size();
+       int unresolvableExportsCount = 0;
+       if ( unresolvableCount != 0 ) {
+               if ( doPrint ) {
+                       if ( _options.printArchPrefix() )
+                               fprintf(stderr, "Undefined symbols for architecture %s:\n", _options.architectureName());
+                       else
+                               fprintf(stderr, "Undefined symbols:\n");
+                       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));
+                               // scan all atoms for references
+                               bool foundAtomReference = printReferencedBy(name, slot);
+                               // scan command line options
+                               if  ( !foundAtomReference ) {
+                                       // might be from -init command line option
+                                       if ( (_options.initFunctionName() != NULL) && (strcmp(name, _options.initFunctionName()) == 0) ) {
+                                               fprintf(stderr, "     -init command line option\n");
+                                       }
+                                       // or might be from exported symbol option
+                                       else if ( _options.hasExportMaskList() && _options.shouldExport(name) ) {
+                                               fprintf(stderr, "     -exported_symbol[s_list] command line option\n");
+                                       }
+                                       // or might be from re-exported symbol option
+                                       else if ( _options.hasReExportList() && _options.shouldReExport(name) ) {
+                                               fprintf(stderr, "     -reexported_symbols_list command line option\n");
+                                       }
+                                       else {
+                                               bool isInitialUndefine = false;
+                                               for (Options::UndefinesIterator uit=_options.initialUndefinesBegin(); uit != _options.initialUndefinesEnd(); ++uit) {
+                                                       if ( strcmp(*uit, name) == 0 ) {
+                                                               isInitialUndefine = true;
+                                                               break;
+                                                       }
+                                               }
+                                               if ( isInitialUndefine )
+                                                       fprintf(stderr, "     -u command line option\n");
+                                       }
+                                       ++unresolvableExportsCount;
+                               }
+                               // be helpful and check for typos
+                               bool printedStart = false;
+                               for (SymbolTable::byNameIterator sit=_symbolTable.begin(); sit != _symbolTable.end(); sit++) {
+                                       const ld::Atom* atom = *sit;
+                                       if ( (atom != NULL) && (strstr(atom->name(), name) != NULL) ) {
+                                               if ( ! printedStart ) {
+                                                       fprintf(stderr, "     (maybe you meant: %s", atom->name());
+                                                       printedStart = true;
+                                               }
+                                               else {
+                                                       fprintf(stderr, ", %s ", atom->name());
+                                               }
+                                       }
+                               }
+                               if ( printedStart )
+                                       fprintf(stderr, ")\n");
+                       }
+               }
+               if ( doError ) 
+                       throw "symbol(s) not found";
+       }
+       
+}
+
+
+
+void Resolver::checkDylibSymbolCollisions()
+{      
+       for (SymbolTable::byNameIterator it=_symbolTable.begin(); it != _symbolTable.end(); it++) {
+               const ld::Atom* atom = *it;
+               if ( atom == NULL )
+                       continue;
+               if ( atom->scope() == ld::Atom::scopeGlobal ) {
+                       // <rdar://problem/5048861> No warning about tentative definition conflicting with dylib definition
+                       // for each tentative definition in symbol table look for dylib that exports same symbol name
+                       if ( atom->definition() == ld::Atom::definitionTentative ) {
+                               _inputFiles.searchLibraries(atom->name(), true, false, *this);
+                       }
+                       // record any overrides of weak symbols in any linked dylib 
+                       if ( (atom->definition() == ld::Atom::definitionRegular) && (atom->symbolTableInclusion() == ld::Atom::symbolTableIn) ) {
+                               if ( _inputFiles.searchWeakDefInDylib(atom->name()) )
+                                       (const_cast<ld::Atom*>(atom))->setOverridesDylibsWeakDef();
+                       }
+               }
+       }
+}      
+
+
+const ld::Atom* Resolver::entryPoint(bool searchArchives)
+{
+       const char* symbolName = NULL;
+       switch ( _options.outputKind() ) {
+               case Options::kDynamicExecutable:
+               case Options::kStaticExecutable:
+               case Options::kDyld:
+               case Options::kPreload:
+                       symbolName = _options.entryName();
+                       break;
+               case Options::kDynamicLibrary:
+                       symbolName = _options.initFunctionName();
+                       break;
+               case Options::kObjectFile:
+               case Options::kDynamicBundle:
+               case Options::kKextBundle:
+                       return NULL;
+                       break;
+       }
+       if ( symbolName != NULL ) {
+               SymbolTable::IndirectBindingSlot slot = _symbolTable.findSlotForName(symbolName);
+               if ( (_internal.indirectBindingTable[slot] == NULL) && searchArchives ) {
+                       // <rdar://problem/7043256> ld64 can not find a -e entry point from an archive                          
+                       _inputFiles.searchLibraries(symbolName, false, true, *this);
+               }
+               if ( _internal.indirectBindingTable[slot] == NULL ) {
+                       if ( strcmp(symbolName, "start") == 0 )
+                               throwf("entry point (%s) undefined.  Usually in crt1.o", symbolName);
+                       else
+                               throwf("entry point (%s) undefined.", symbolName);
+               }
+               return _internal.indirectBindingTable[slot];
+       }
+       return NULL;
+}
+
+
+void Resolver::fillInHelpersInInternalState()
+{
+       // look up well known atoms
+       bool needsStubHelper = true;
+       switch ( _options.outputKind() ) {
+               case Options::kDynamicExecutable:
+               case Options::kDynamicLibrary:
+               case Options::kDynamicBundle:
+                       needsStubHelper = true;
+                       break;
+               case Options::kDyld:
+               case Options::kKextBundle:
+               case Options::kObjectFile:
+               case Options::kStaticExecutable:
+               case Options::kPreload:
+                       needsStubHelper = false;
+                       break;
+       }
+       
+       _internal.classicBindingHelper = NULL;
+       if ( needsStubHelper && !_options.makeCompressedDyldInfo() ) { 
+               // "dyld_stub_binding_helper" comes from .o file, so should already exist in symbol table
+               if ( _symbolTable.hasName("dyld_stub_binding_helper") ) {
+                       SymbolTable::IndirectBindingSlot slot = _symbolTable.findSlotForName("dyld_stub_binding_helper");
+                       _internal.classicBindingHelper = _internal.indirectBindingTable[slot];
+               }
+       }
+       
+       _internal.lazyBindingHelper = NULL;
+       if ( _options.usingLazyDylibLinking() ) {
+               // "dyld_lazy_dylib_stub_binding_helper" comes from lazydylib1.o file, so should already exist in symbol table
+               if ( _symbolTable.hasName("dyld_lazy_dylib_stub_binding_helper") ) {
+                       SymbolTable::IndirectBindingSlot slot = _symbolTable.findSlotForName("dyld_lazy_dylib_stub_binding_helper");
+                       _internal.lazyBindingHelper = _internal.indirectBindingTable[slot];
+               }
+               if ( _internal.lazyBindingHelper == NULL )
+                       throw "symbol dyld_lazy_dylib_stub_binding_helper not defined (usually in lazydylib1.o)";
+       }
+       
+       _internal.compressedFastBinderProxy = NULL;
+       if ( needsStubHelper && _options.makeCompressedDyldInfo() ) { 
+               // "dyld_stub_binder" comes from libSystem.dylib so will need to manually resolve
+               if ( !_symbolTable.hasName("dyld_stub_binder") ) {
+                       _inputFiles.searchLibraries("dyld_stub_binder", true, false, *this);
+               }
+               if ( _symbolTable.hasName("dyld_stub_binder") ) {
+                       SymbolTable::IndirectBindingSlot slot = _symbolTable.findSlotForName("dyld_stub_binder");
+                       _internal.compressedFastBinderProxy = _internal.indirectBindingTable[slot];
+               }
+               if ( _internal.compressedFastBinderProxy == NULL ) {
+                       if ( _options.undefinedTreatment() != Options::kUndefinedError ) {
+                               // make proxy
+                               _internal.compressedFastBinderProxy = new UndefinedProxyAtom("dyld_stub_binder");
+                               this->doAtom(*_internal.compressedFastBinderProxy);
+                       }
+                       else {
+                               warning("symbol dyld_stub_binder not found, normally in libSystem.dylib");
+                       }
+               }
+       }
+}
+
+
+void Resolver::fillInInternalState()
+{
+       // store atoms into their final section
+       for (std::vector<const ld::Atom*>::iterator it = _atoms.begin(); it != _atoms.end(); ++it) {
+               _internal.addAtom(**it);
+       }
+       
+       // <rdar://problem/7783918> make sure there is a __text section so that codesigning works
+       if ( (_options.outputKind() == Options::kDynamicLibrary) || (_options.outputKind() == Options::kDynamicBundle) )
+               _internal.getFinalSection(ld::Section("__TEXT", "__text", ld::Section::typeCode));
+
+       // add entry point
+       _internal.entryPoint = this->entryPoint(true);
+}
+
+
+
+void Resolver::removeCoalescedAwayAtoms()
+{
+       _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), AtomCoalescedAway()), _atoms.end());
+}
+
+void Resolver::linkTimeOptimize()
+{
+       // only do work here if some llvm obj files where loaded
+       if ( ! _haveLLVMObjs )
+               return;
+       
+       // run LLVM lto code-gen
+       lto::OptimizeOptions optOpt;
+       optOpt.outputFilePath                           = _options.outputFilePath();
+       optOpt.tmpObjectFilePath                        = _options.tempLtoObjectPath();
+       optOpt.allGlobalsAReDeadStripRoots      = _options.allGlobalsAreDeadStripRoots();
+       optOpt.verbose                                          = _options.verbose();
+       optOpt.saveTemps                                        = _options.saveTempFiles();
+       optOpt.pie                                                      = _options.positionIndependentExecutable();
+       optOpt.mainExecutable                           = _options.linkingMainExecutable();;
+       optOpt.staticExecutable                         = (_options.outputKind() == Options::kStaticExecutable);
+       optOpt.relocatable                                      = (_options.outputKind() == Options::kObjectFile);
+       optOpt.allowTextRelocs                          = _options.allowTextRelocs();
+       optOpt.linkerDeadStripping                      = _options.deadCodeStrip();
+       optOpt.arch                                                     = _options.architecture();
+       optOpt.llvmOptions                                      = &_options.llvmOptions();
+       
+       std::vector<const ld::Atom*>            newAtoms;
+       std::vector<const char*>                        additionalUndefines; 
+       if ( ! lto::optimize(_atoms, _internal, _inputFiles.nextInputOrdinal(), optOpt, *this, newAtoms, additionalUndefines) )
+               return; // if nothing done
+               
+       
+       // add all newly created atoms to _atoms and update symbol table
+       for(std::vector<const ld::Atom*>::iterator it = newAtoms.begin(); it != newAtoms.end(); ++it)
+               this->doAtom(**it);
+               
+       // 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);
+                       }
+               }
+       }
+       
+       // 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
+               if ( ! _symbolTable.hasName(targetName) ) {
+                       _inputFiles.searchLibraries(targetName, true, true, *this);
+               }
+       }
+       _addToFinalSection = false;
+
+       // if -dead_strip on command line
+       if ( _options.deadCodeStrip() ) {
+               // clear liveness bit
+               for (std::vector<const ld::Atom*>::const_iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
+                       (const_cast<ld::Atom*>(*it))->setLive((*it)->dontDeadStrip());
+               }
+               // 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
+               this->checkUndefines(true);
+
+               // check new code does not override some dylib
+               this->checkDylibSymbolCollisions();
+       }
+}
+
+
+void Resolver::resolve()
+{
+       this->initializeState();
+       this->buildAtomList();
+       this->addInitialUndefines();
+       this->fillInHelpersInInternalState();
+       this->resolveUndefines();
+       this->deadStripOptimize();
+       this->checkUndefines();
+       this->checkDylibSymbolCollisions();
+       this->removeCoalescedAwayAtoms();
+       this->fillInInternalState();
+       this->linkTimeOptimize();
+}
+
+
+
+} // namespace tool 
+} // namespace ld 
+
+
+
diff --git a/src/ld/Resolver.h b/src/ld/Resolver.h
new file mode 100644 (file)
index 0000000..1202fc7
--- /dev/null
@@ -0,0 +1,148 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __RESOLVER_H__
+#define __RESOLVER_H__
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/sysctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+#include <mach/mach_time.h>
+#include <mach/vm_statistics.h>
+#include <mach/mach_init.h>
+#include <mach/mach_host.h>
+#include <dlfcn.h>
+#include <mach-o/dyld.h>
+
+#include <vector>
+
+#include "Options.h"
+#include "ld.hpp"
+#include "SymbolTable.h"
+
+
+namespace ld {
+namespace tool {
+
+
+
+
+class Resolver : public ld::File::AtomHandler
+{
+public:
+                                                       Resolver(const Options& opts, const InputFiles& inputs, ld::Internal& state) 
+                                                               : _options(opts), _inputFiles(inputs), _internal(state), 
+                                                                 _symbolTable(opts, state.indirectBindingTable),
+                                                                 _haveLLVMObjs(false), _addToFinalSection(false),
+                                                                 _completedInitialObjectFiles(false) {}
+                                                               
+
+               virtual void            doAtom(const ld::Atom&);
+               virtual void            doFile(const class File&);
+               
+               void                            resolve();
+
+       
+private:
+       struct WhyLiveBackChain
+       {
+               WhyLiveBackChain*       previous;
+               const ld::Atom*         referer;
+       };
+
+       void                                    initializeState();
+       void                                    buildAtomList();
+       void                                    addInitialUndefines();
+       void                                    deadStripOptimize();
+       void                                    resolveUndefines();
+       void                                    checkUndefines(bool force=false);
+       void                                    checkDylibSymbolCollisions();
+       void                                    tentativeOverrideOfDylib(ld::Atom&);
+       void                                    fillInInternalState();
+       void                                    fillInHelpersInInternalState();
+       void                                    removeCoalescedAwayAtoms();
+       void                                    linkTimeOptimize();
+       void                                    convertReferencesToIndirect(const ld::Atom& atom);
+       const ld::Atom*                 entryPoint(bool searchArchives);
+       void                                    markLive(const ld::Atom& atom, WhyLiveBackChain* previous);
+       bool                                    isDtraceProbe(ld::Fixup::Kind kind);
+       void                                    liveUndefines(std::vector<const char*>&);
+       static unsigned int             ppcSubTypeIndex(uint32_t subtype);
+       bool                                    printReferencedBy(const char* name, SymbolTable::IndirectBindingSlot slot);
+                       
+
+       class CStringEquals {
+       public:
+               bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+       };
+       typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals>  StringSet;
+
+       class NotLive {
+       public:
+               bool operator()(const ld::Atom* atom) const {
+                       return ! (atom->live() || atom->dontDeadStrip());
+               }
+       };
+
+       class AtomCoalescedAway {
+       public:
+               bool operator()(const ld::Atom* atom) const {
+                       return atom->coalescedAway();
+               }
+       };
+
+       const Options&                                  _options;
+       const 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;
+};
+
+
+class DeadStripResolver   
+{
+public:
+
+       
+private:
+
+};
+
+} // namespace tool 
+} // namespace ld 
+
+
+
+#endif // __RESOLVER_H__
diff --git a/src/ld/SectCreate.h b/src/ld/SectCreate.h
deleted file mode 100644 (file)
index d5c7f4e..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
- *
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
- */
-
-
-#ifndef __SECTCREATE__
-#define __SECTCREATE__
-
-
-#include "ObjectFile.h"
-
-namespace SectCreate {
-
-       extern ObjectFile::Reader* MakeReader(const char* segmentName, const char* sectionName, const char* path, const uint8_t fileContent[], uint64_t fileLength);
-
-};
-
-
-#endif
-
-
-
-
diff --git a/src/ld/SymbolTable.cpp b/src/ld/SymbolTable.cpp
new file mode 100644 (file)
index 0000000..f9ed04c
--- /dev/null
@@ -0,0 +1,721 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
+ *
+ * Copyright (c) 2009-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/sysctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+#include <assert.h>
+
+#include <string>
+#include <map>
+#include <set>
+#include <vector>
+#include <algorithm>
+#include <ext/hash_map>
+#include <ext/hash_set>
+
+#include "Options.h"
+
+#include "ld.hpp"
+#include "InputFiles.h"
+#include "SymbolTable.h"
+
+
+
+namespace ld {
+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)  
+{  
+       _s_indirectBindingTable = this;
+       _s_doDemangle = _options.demangleSymbols();
+}
+
+
+size_t SymbolTable::ContentFuncs::operator()(const ld::Atom* atom) const
+{
+       return atom->contentHash(*_s_indirectBindingTable);
+}
+
+bool SymbolTable::ContentFuncs::operator()(const ld::Atom* left, const ld::Atom* right) const
+{
+       return (memcmp(left->rawContentPointer(), right->rawContentPointer(), left->size()) == 0);
+}
+
+
+
+size_t SymbolTable::CStringHashFuncs::operator()(const ld::Atom* atom) const
+{
+       return atom->contentHash(*_s_indirectBindingTable);
+}
+
+bool SymbolTable::CStringHashFuncs::operator()(const ld::Atom* left, const ld::Atom* right) const
+{
+       return (strcmp((char*)left->rawContentPointer(), (char*)right->rawContentPointer()) == 0);
+}
+
+
+size_t SymbolTable::UTF16StringHashFuncs::operator()(const ld::Atom* atom) const
+{
+       return atom->contentHash(*_s_indirectBindingTable);
+}
+
+bool SymbolTable::UTF16StringHashFuncs::operator()(const ld::Atom* left, const ld::Atom* right) const
+{
+       if ( left == right )
+               return true;
+       const void* leftContent = left->rawContentPointer();
+       const void* rightContent = right->rawContentPointer();
+       unsigned int amount = left->size()-2;
+       bool result = (memcmp(leftContent, rightContent, amount) == 0);
+       return result;
+}
+
+
+size_t SymbolTable::ReferencesHashFuncs::operator()(const ld::Atom* atom) const
+{
+       return atom->contentHash(*_s_indirectBindingTable);
+}
+
+bool SymbolTable::ReferencesHashFuncs::operator()(const ld::Atom* left, const ld::Atom* right) const
+{
+       return left->canCoalesceWith(*right, *_s_indirectBindingTable);
+}
+
+
+
+bool SymbolTable::addByName(const ld::Atom& newAtom, bool ignoreDuplicates)
+{
+       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 ) {
+                                                               // 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;
+                                                       }
+                                               }
+                                               else {
+                                                       if ( newAtom.combine() == ld::Atom::combineByName ) {
+                                                               // existing not-weak, new is weak
+                                                               useNew = false;
+                                                       }
+                                                       else {
+                                                               // existing not-weak, new is not-weak
+                                                               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());
+                                                               }
+                                                       }
+                                               }
+                                               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());
+                                               }
+                                               break;
+                                       case ld::Atom::definitionAbsolute:
+                                               throwf("duplicate symbol %s in %s and %s", name, newAtom.file()->path(), existingAtom->file()->path());
+                                       case ld::Atom::definitionProxy:
+                                               // ignore external atom, because we already have a one
+                                               useNew = false;
+                                               break;
+                               }
+                               break;
+                       case ld::Atom::definitionTentative:
+                               switch ( newAtom.definition() ) {
+                                       case ld::Atom::definitionRegular:
+                                               // replace existing tentative atom with regular one
+                                               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());
+                                               }
+                                               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());
+                                               }
+                                               break;
+                                       case ld::Atom::definitionAbsolute:
+                                               // replace tentative with absolute
+                                               useNew = true;
+                                               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());
+                                               }
+                                               break;
+                               }
+                               break;
+                       case ld::Atom::definitionAbsolute:
+                               switch ( newAtom.definition() ) {
+                                       case ld::Atom::definitionRegular:
+                                               throwf("duplicate symbol %s in %s and %s", name, newAtom.file()->path(), existingAtom->file()->path());
+                                       case ld::Atom::definitionTentative:
+                                               // ignore new tentative atom, because we already have a regular one
+                                               useNew = false;
+                                               break;
+                                       case ld::Atom::definitionAbsolute:
+                                               throwf("duplicate symbol %s in %s and %s", name, newAtom.file()->path(), existingAtom->file()->path());
+                                       case ld::Atom::definitionProxy:
+                                               // ignore external atom, because we already have a one
+                                               useNew = false;
+                                               break;
+                               }
+                               break;
+                       case ld::Atom::definitionProxy:
+                               switch ( newAtom.definition() ) {
+                                       case ld::Atom::definitionRegular:
+                                               // replace external atom with regular one
+                                               useNew = true;
+                                               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());
+                                               }
+                                               break;
+                                       case ld::Atom::definitionAbsolute:
+                                               // replace external atom with absolute one
+                                               useNew = true;
+                                               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());
+                                               }
+                                               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());
+       }
+       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 ) {
+                               _hasExternalTentativeDefinitions = true;
+                       }
+               }
+       }
+       else {
+               markCoalescedAway(&newAtom);
+       }
+       // return if existing atom in symbol table was replaced
+       return useNew && (existingAtom != NULL);
+}
+
+
+bool SymbolTable::addByContent(const ld::Atom& newAtom)
+{
+       bool useNew = true;
+       const ld::Atom* existingAtom;
+       IndirectBindingSlot slot = this->findSlotForContent(&newAtom, &existingAtom);
+       //fprintf(stderr, "addByContent(%p) name=%s, slot=%u, existing=%p\n", &newAtom, newAtom.name(), slot, existingAtom);
+       if ( existingAtom != NULL ) {
+               // use existing unless new one has greater alignment requirements
+               useNew = ( newAtom.alignment().trailingZeros() > existingAtom->alignment().trailingZeros() );
+       }
+       if ( useNew ) {
+               _indirectBindingTable[slot] = &newAtom;
+               if ( existingAtom != NULL ) 
+                       markCoalescedAway(existingAtom);
+       }
+       else {
+               _indirectBindingTable[slot] = existingAtom;
+               if ( existingAtom != &newAtom )
+                       markCoalescedAway(&newAtom);
+       }
+       // return if existing atom in symbol table was replaced
+       return useNew && (existingAtom != NULL);
+}
+
+bool SymbolTable::addByReferences(const ld::Atom& newAtom)
+{
+       bool useNew = true;
+       const ld::Atom* existingAtom;
+       IndirectBindingSlot slot = this->findSlotForReferences(&newAtom, &existingAtom);
+       //fprintf(stderr, "addByReferences(%p) name=%s, slot=%u, existing=%p\n", &newAtom, newAtom.name(), slot, existingAtom);
+       if ( existingAtom != NULL ) {
+               // use existing unless new one has greater alignment requirements
+               useNew = ( newAtom.alignment().trailingZeros() > existingAtom->alignment().trailingZeros() );
+       }
+       if ( useNew ) {
+               _indirectBindingTable[slot] = &newAtom;
+               if ( existingAtom != NULL ) 
+                       markCoalescedAway(existingAtom);
+       }
+       else {
+               if ( existingAtom != &newAtom )
+                       markCoalescedAway(&newAtom);
+       }
+       // return if existing atom in symbol table was replaced
+       return useNew && (existingAtom != NULL);
+}
+
+
+bool SymbolTable::add(const ld::Atom& atom, bool ignoreDuplicates)
+{
+       //fprintf(stderr, "SymbolTable::add(%p), name=%s\n", &atom, atom.name());
+       assert(atom.scope() != ld::Atom::scopeTranslationUnit);
+       switch ( atom.combine() ) {
+               case ld::Atom::combineNever:
+               case ld::Atom::combineByName:
+                       return this->addByName(atom, ignoreDuplicates);
+                       break;
+               case ld::Atom::combineByNameAndContent:
+                       return this->addByContent(atom);
+                       break;
+               case ld::Atom::combineByNameAndReferences:
+                       return this->addByReferences(atom);
+                       break;
+       }
+
+       return false;
+}
+
+void SymbolTable::markCoalescedAway(const ld::Atom* atom)
+{
+       // remove this from list of all atoms used
+       //fprintf(stderr, "markCoalescedAway(%p) from %s\n", atom, atom->file()->path());
+       (const_cast<ld::Atom*>(atom))->setCoalescedAway();
+       
+       //
+       // The fixupNoneGroupSubordinate* fixup kind is used to model group comdat.  
+       // The "signature" atom in the group has a fixupNoneGroupSubordinate* fixup to
+       // all other members of the group.  So, if the signature atom is 
+       // coalesced away, all other atoms in the group should also be removed.  
+       //
+       for (ld::Fixup::iterator fit=atom->fixupsBegin(), fend=atom->fixupsEnd(); fit != fend; ++fit) { 
+               switch ( fit->kind ) {
+                       case ld::Fixup::kindNoneGroupSubordinate:
+                       case ld::Fixup::kindNoneGroupSubordinateFDE:
+                       case ld::Fixup::kindNoneGroupSubordinateLSDA:
+                               assert(fit->binding == ld::Fixup::bindingDirectlyBound);
+                               this->markCoalescedAway(fit->u.target);
+                               break;
+                       default:
+                               break;
+               }
+       }
+
+}
+
+void SymbolTable::undefines(std::vector<const char*>& undefs)
+{
+       // return all names in _byNameTable that have no associated atom
+       for (NameToSlot::iterator it=_byNameTable.begin(); it != _byNameTable.end(); ++it) {
+               //fprintf(stderr, "  _byNameTable[%s] = slot %d which has atom %p\n", it->first, it->second, _indirectBindingTable[it->second]);
+               if ( _indirectBindingTable[it->second] == NULL )
+                       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());
+}
+
+
+void SymbolTable::tentativeDefs(std::vector<const char*>& tents)
+{
+       // return all names in _byNameTable that have no associated atom
+       for (NameToSlot::iterator it=_byNameTable.begin(); it != _byNameTable.end(); ++it) {
+               const char* name = it->first;
+               const ld::Atom* atom = _indirectBindingTable[it->second];
+               if ( (atom != NULL) && (atom->definition() == ld::Atom::definitionTentative) )
+                       tents.push_back(name);
+       }
+       std::sort(tents.begin(), tents.end());
+}
+
+
+bool SymbolTable::hasName(const char* name)                    
+{ 
+       NameToSlot::iterator pos = _byNameTable.find(name);
+       if ( pos == _byNameTable.end() ) 
+               return false;
+       return (_indirectBindingTable[pos->second] != NULL); 
+}
+
+// find existing or create new slot
+SymbolTable::IndirectBindingSlot SymbolTable::findSlotForName(const char* name)
+{
+       NameToSlot::iterator pos = _byNameTable.find(name);
+       if ( pos != _byNameTable.end() ) 
+               return pos->second;
+       // create new slot for this name
+       SymbolTable::IndirectBindingSlot slot = _indirectBindingTable.size();
+       _indirectBindingTable.push_back(NULL);
+       _byNameTable[name] = slot;
+       _byNameReverseTable[slot] = name;
+       return slot;
+}
+
+
+// find existing or create new slot
+SymbolTable::IndirectBindingSlot SymbolTable::findSlotForContent(const ld::Atom* atom, const ld::Atom** existingAtom)
+{
+       //fprintf(stderr, "findSlotForContent(%p)\n", atom);
+       SymbolTable::IndirectBindingSlot slot = 0;
+       UTF16StringToSlot::iterator upos;
+       CStringToSlot::iterator cspos;
+       ContentToSlot::iterator pos;
+       switch ( atom->section().type() ) {
+               case ld::Section::typeCString:
+                       cspos = _cstringTable.find(atom);
+                       if ( cspos != _cstringTable.end() ) {
+                               *existingAtom = _indirectBindingTable[cspos->second];
+                               return cspos->second;
+                       }
+                       slot = _indirectBindingTable.size();
+                       _cstringTable[atom] = slot;
+                       break;
+               case ld::Section::typeNonStdCString:
+                       {
+                               // use seg/sect name is key to map to avoid coalescing across segments and sections
+                               char segsect[64];
+                               sprintf(segsect, "%s/%s", atom->section().segmentName(), atom->section().sectionName());
+                               NameToMap::iterator mpos = _nonStdCStringSectionToMap.find(segsect);
+                               CStringToSlot* map = NULL;
+                               if ( mpos == _nonStdCStringSectionToMap.end() ) {
+                                       map = new CStringToSlot();
+                                       _nonStdCStringSectionToMap[strdup(segsect)] = map;
+                               }
+                               else {
+                                       map = mpos->second;
+                               }
+                               cspos = map->find(atom);
+                               if ( cspos != map->end() ) {
+                                       *existingAtom = _indirectBindingTable[cspos->second];
+                                       return cspos->second;
+                               }
+                               slot = _indirectBindingTable.size();
+                               map->operator[](atom) = slot;
+                       }
+                       break;
+               case ld::Section::typeUTF16Strings:
+                       upos = _utf16Table.find(atom);
+                       if ( upos != _utf16Table.end() ) {
+                               *existingAtom = _indirectBindingTable[upos->second];
+                               return upos->second;
+                       }
+                       slot = _indirectBindingTable.size();
+                       _utf16Table[atom] = slot;
+                       break;
+               case ld::Section::typeLiteral4:
+                       pos = _literal4Table.find(atom);
+                       if ( pos != _literal4Table.end() ) {
+                               *existingAtom = _indirectBindingTable[pos->second];
+                               return pos->second;
+                       }
+                       slot = _indirectBindingTable.size();
+                       _literal4Table[atom] = slot;
+                       break;
+               case ld::Section::typeLiteral8:
+                       pos = _literal8Table.find(atom);
+                       if ( pos != _literal8Table.end() ) {
+                               *existingAtom = _indirectBindingTable[pos->second];
+                               return pos->second;
+                       }
+                       slot = _indirectBindingTable.size();
+                       _literal8Table[atom] = slot;
+                       break;
+               case ld::Section::typeLiteral16:
+                       pos = _literal16Table.find(atom);
+                       if ( pos != _literal16Table.end() ) {
+                               *existingAtom = _indirectBindingTable[pos->second];
+                               return pos->second;
+                       }
+                       slot = _indirectBindingTable.size();
+                       _literal16Table[atom] = slot;
+                       break;
+               default:
+                       assert(0 && "section type does not support coalescing by content");
+       }
+       _indirectBindingTable.push_back(atom); 
+       *existingAtom = NULL;
+       return slot;
+}
+
+
+
+// find existing or create new slot
+SymbolTable::IndirectBindingSlot SymbolTable::findSlotForReferences(const ld::Atom* atom, const ld::Atom** existingAtom)
+{
+       //fprintf(stderr, "findSlotForReferences(%p)\n", atom);
+       
+       SymbolTable::IndirectBindingSlot slot = 0;
+       ReferencesToSlot::iterator pos;
+       switch ( atom->section().type() ) {
+               case ld::Section::typeNonLazyPointer:           
+                       pos = _nonLazyPointerTable.find(atom);
+                       if ( pos != _nonLazyPointerTable.end() ) {
+                               *existingAtom = _indirectBindingTable[pos->second];
+                               return pos->second;
+                       }
+                       slot = _indirectBindingTable.size();
+                       _nonLazyPointerTable[atom] = slot;
+                       break;
+               case ld::Section::typeCFString:
+                       pos = _cfStringTable.find(atom);
+                       if ( pos != _cfStringTable.end() ) {
+                               *existingAtom = _indirectBindingTable[pos->second];
+                               return pos->second;
+                       }
+                       slot = _indirectBindingTable.size();
+                       _cfStringTable[atom] = slot;
+                       break;
+               case ld::Section::typeObjCClassRefs:
+                       pos = _objc2ClassRefTable.find(atom);
+                       if ( pos != _objc2ClassRefTable.end() ) {
+                               *existingAtom = _indirectBindingTable[pos->second];
+                               return pos->second;
+                       }
+                       slot = _indirectBindingTable.size();
+                       _objc2ClassRefTable[atom] = slot;
+                       break;
+               case ld::Section::typeCStringPointer:
+                       pos = _pointerToCStringTable.find(atom);
+                       if ( pos != _pointerToCStringTable.end() ) {
+                               *existingAtom = _indirectBindingTable[pos->second];
+                               return pos->second;
+                       }
+                       slot = _indirectBindingTable.size();
+                       _pointerToCStringTable[atom] = slot;
+                       break;
+               default:
+                       assert(0 && "section type does not support coalescing by references");
+       }
+       _indirectBindingTable.push_back(atom);
+       *existingAtom = NULL;
+       return slot;
+}
+
+
+const char*    SymbolTable::indirectName(IndirectBindingSlot slot) const
+{
+       assert(slot < _indirectBindingTable.size());
+       const ld::Atom* target = _indirectBindingTable[slot];
+       if ( target != NULL )  {
+               return target->name();
+       }
+       // handle case when by-name reference is indirected and no atom yet in _byNameTable
+       SlotToName::const_iterator pos = _byNameReverseTable.find(slot);
+       if ( pos != _byNameReverseTable.end() )
+               return pos->second;
+       assert(0);
+       return NULL;
+}
+
+const ld::Atom* SymbolTable::indirectAtom(IndirectBindingSlot slot) const
+{
+       assert(slot < _indirectBindingTable.size());
+       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", 
+//                             _cstringTable.size(), _cstringTable.bucket_count(), cstringHashCount);
+       int count[11];
+       for(unsigned int b=0; b < 11; ++b) {
+               count[b] = 0;
+       }
+       for(unsigned int i=0; i < _cstringTable.bucket_count(); ++i) {
+               unsigned int n = _cstringTable.elems_in_bucket(i);
+               if ( n < 10 ) 
+                       count[n] += 1;
+               else
+                       count[10] += 1;
+       }
+       fprintf(stderr, "cstring table distribution\n");
+       for(unsigned int b=0; b < 11; ++b) {
+               fprintf(stderr, "%u buckets have %u elements\n", count[b], b);
+       }
+       fprintf(stderr, "indirect table size: %lu\n", _indirectBindingTable.size());
+       fprintf(stderr, "by-name table size: %lu\n", _byNameTable.size());
+//     fprintf(stderr, "by-content table size: %lu, hash count: %u, equals count: %u, lookup count: %u\n", 
+//                                             _byContentTable.size(), contentHashCount, contentEqualCount, contentLookupCount);
+//     fprintf(stderr, "by-ref table size: %lu, hashed count: %u, equals count: %u, lookup count: %u, insert count: %u\n", 
+//                                             _byReferencesTable.size(), refHashCount, refEqualsCount, refLookupCount, refInsertCount);
+
+       //ReferencesHash obj;
+       //for(ReferencesHashToSlot::iterator it=_byReferencesTable.begin(); it != _byReferencesTable.end(); ++it) {
+       //      if ( obj.operator()(it->first) == 0x2F3AC0EAC744EA70 ) {
+       //              fprintf(stderr, "hash=0x2F3AC0EAC744EA70 for %p %s from %s\n", it->first, it->first->name(), it->first->file()->path());
+       //      
+       //      }
+       //}
+       
+}
+
+} // namespace tool 
+} // namespace ld 
+
diff --git a/src/ld/SymbolTable.h b/src/ld/SymbolTable.h
new file mode 100644 (file)
index 0000000..f352a51
--- /dev/null
@@ -0,0 +1,165 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __SYMBOL_TABLE_H__
+#define __SYMBOL_TABLE_H__
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/sysctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+#include <mach/mach_time.h>
+#include <mach/vm_statistics.h>
+#include <mach/mach_init.h>
+#include <mach/mach_host.h>
+#include <dlfcn.h>
+#include <mach-o/dyld.h>
+
+#include <vector>
+#include <ext/hash_map>
+
+#include "Options.h"
+#include "ld.hpp"
+
+namespace ld {
+namespace tool {
+
+
+class SymbolTable : public ld::IndirectBindingTable
+{
+public:
+       typedef uint32_t IndirectBindingSlot;
+
+private:
+       class CStringEquals {
+       public:
+               bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+       };
+       typedef __gnu_cxx::hash_map<const char*, IndirectBindingSlot, __gnu_cxx::hash<const char*>, CStringEquals> NameToSlot;
+
+       class ContentFuncs {
+       public:
+               size_t  operator()(const ld::Atom*) const;
+               bool    operator()(const ld::Atom* left, const ld::Atom* right) const;
+       };
+       typedef __gnu_cxx::hash_map<const ld::Atom*, IndirectBindingSlot, ContentFuncs, ContentFuncs> ContentToSlot;
+
+       class ReferencesHashFuncs {
+       public:
+               size_t  operator()(const ld::Atom*) const;
+               bool    operator()(const ld::Atom* left, const ld::Atom* right) const;
+       };
+       typedef __gnu_cxx::hash_map<const ld::Atom*, IndirectBindingSlot, ReferencesHashFuncs, ReferencesHashFuncs> ReferencesToSlot;
+
+       class CStringHashFuncs {
+       public:
+               size_t  operator()(const ld::Atom*) const;
+               bool    operator()(const ld::Atom* left, const ld::Atom* right) const;
+       };
+       typedef __gnu_cxx::hash_map<const ld::Atom*, IndirectBindingSlot, CStringHashFuncs, CStringHashFuncs> CStringToSlot;
+
+       class UTF16StringHashFuncs {
+       public:
+               size_t  operator()(const ld::Atom*) const;
+               bool    operator()(const ld::Atom* left, const ld::Atom* right) const;
+       };
+       typedef __gnu_cxx::hash_map<const ld::Atom*, IndirectBindingSlot, UTF16StringHashFuncs, UTF16StringHashFuncs> UTF16StringToSlot;
+
+       typedef std::map<IndirectBindingSlot, const char*> SlotToName;
+       typedef __gnu_cxx::hash_map<const char*, CStringToSlot*, __gnu_cxx::hash<const char*>, CStringEquals> NameToMap;
+       
+public:
+
+       class byNameIterator {
+       public:
+               byNameIterator&                 operator++(int) { ++_nameTableIterator; return *this; }
+               const ld::Atom*                 operator*() { return _slotTable[_nameTableIterator->second]; }
+               bool                                    operator!=(const byNameIterator& lhs) { return _nameTableIterator != lhs._nameTableIterator; }
+
+       private:
+               friend class SymbolTable;
+                                                               byNameIterator(NameToSlot::iterator it, std::vector<const ld::Atom*>& indirectTable)
+                                                                       : _nameTableIterator(it), _slotTable(indirectTable) {} 
+               
+               NameToSlot::iterator                    _nameTableIterator;
+               std::vector<const ld::Atom*>&   _slotTable;
+       };
+       
+                                               SymbolTable(const Options& opts, std::vector<const ld::Atom*>& ibt);
+
+       bool                            add(const ld::Atom& atom, bool ignoreDuplicates);
+       IndirectBindingSlot     findSlotForName(const char* name);
+       IndirectBindingSlot     findSlotForContent(const ld::Atom* atom, const ld::Atom** existingAtom);
+       IndirectBindingSlot     findSlotForReferences(const ld::Atom* atom, const ld::Atom** existingAtom);
+       const ld::Atom*         atomForSlot(IndirectBindingSlot s)      { return _indirectBindingTable[s]; }
+       unsigned int            updateCount()                                           { return _indirectBindingTable.size(); }
+       void                            undefines(std::vector<const char*>& undefines);
+       void                            tentativeDefs(std::vector<const char*>& undefines);
+       bool                            hasName(const char* name);
+       bool                            hasExternalTentativeDefinitions()       { return _hasExternalTentativeDefinitions; }
+       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;
+
+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);
+
+       const Options&                                  _options;
+       NameToSlot                                              _byNameTable;
+       SlotToName                                              _byNameReverseTable;
+       ContentToSlot                                   _literal4Table;
+       ContentToSlot                                   _literal8Table;
+       ContentToSlot                                   _literal16Table;
+       UTF16StringToSlot                               _utf16Table;
+       CStringToSlot                                   _cstringTable;
+       NameToMap                                               _nonStdCStringSectionToMap;
+       ReferencesToSlot                                _nonLazyPointerTable;
+       ReferencesToSlot                                _cfStringTable;
+       ReferencesToSlot                                _objc2ClassRefTable;
+       ReferencesToSlot                                _pointerToCStringTable;
+       std::vector<const ld::Atom*>&   _indirectBindingTable;
+       bool                                                    _hasExternalTentativeDefinitions;
+       
+       static bool                                             _s_doDemangle;
+
+};
+
+} // namespace tool 
+} // namespace ld 
+
+
+#endif // __SYMBOL_TABLE_H__
index 971e616e5b68faca97607a8870608b1006cd18c1..c367d00615dfeebb035f895dd66839a652776db6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005-2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -345,6 +345,8 @@ line_at_eof (struct line_reader_data * lnd)
   return lnd->cpos == lnd->end;
 }
 
+static const bool verbose = false;
+
 static bool
 next_state (struct line_reader_data *lnd)
 {
@@ -373,28 +375,34 @@ next_state (struct line_reader_data *lnd)
        case DW_LNS_extended_op:
          {
            uint64_t sz = read_uleb128 (lnd);
-           const uint8_t * op = lnd->cpos;
+           const uint8_t * eop = lnd->cpos;
            
-           if ((uint64_t)(lnd->end - op) < sz || sz == 0)
+           if ((uint64_t)(lnd->end - eop) < sz || sz == 0)
              return false;
            lnd->cpos += sz;
-           switch (*op++)
+           switch (*eop++)
              {
              case DW_LNE_end_sequence:
+             if (verbose) fprintf(stderr, "DW_LNE_end_sequence\n");
                lnd->cur.end_of_sequence = true;
                return true;
                
              case DW_LNE_set_address:
-               if (sz == 9)
-                 lnd->cur.pc = read_64 (op);
-               else if (sz == 5)
-                 lnd->cur.pc = read_32 (op);
+               if (sz == 9) {
+                 lnd->cur.pc = read_64 (eop);
+                 if (verbose) fprintf(stderr, "DW_LNE_set_address(0x%08llX)\n", lnd->cur.pc);
+               }
+               else if (sz == 5) {
+                 lnd->cur.pc = read_32 (eop);
+                 if (verbose) fprintf(stderr, "DW_LNE_set_address(0x%08llX)\n", lnd->cur.pc);
+               }
                else
                  return false;
                break;
                
              case DW_LNE_define_file:
                {
+                 if (verbose) fprintf(stderr, "DW_LNE_define_file\n");
                  const uint8_t * * filenames;
                  filenames = realloc 
                    (lnd->filenames, 
@@ -402,9 +410,9 @@ next_state (struct line_reader_data *lnd)
                  if (! filenames)
                    return false;
                  /* Check for zero-termination.  */
-                 if (! memchr (op, 0, lnd->cpos - op))
+                 if (! memchr (eop, 0, lnd->cpos - eop))
                    return false;
-                 filenames[lnd->numfile++] = op;
+                 filenames[lnd->numfile++] = eop;
                  lnd->filenames = filenames;
 
                  /* There's other data here, like file sizes and modification
@@ -414,40 +422,41 @@ next_state (struct line_reader_data *lnd)
                
              default:
                /* Don't understand it, so skip it.  */
+               if (verbose) fprintf(stderr, "DW_LNS_extended_op unknown\n");
                break;
              }
            break;
          }
          
        case DW_LNS_copy:
-       //fprintf(stderr, "DW_LNS_copy\n");
+         if (verbose) fprintf(stderr, "DW_LNS_copy\n");
          return true;
        case DW_LNS_advance_pc:
-       //fprintf(stderr, "DW_LNS_advance_pc\n");
          tmp = read_uleb128 (lnd);
          if (tmp == (uint64_t) -1)
            return false;
          lnd->cur.pc += tmp * lnd->minimum_instruction_length;
+         if (verbose) fprintf(stderr, "DW_LNS_advance_pc(0x%08llX)\n", lnd->cur.pc);
          break;
        case DW_LNS_advance_line:
-       //fprintf(stderr, "DW_LNS_advance_line\n");
          lnd->cur.line += read_sleb128 (lnd);
+         if (verbose) fprintf(stderr, "DW_LNS_advance_line(%lld)\n", lnd->cur.line);
          break;
        case DW_LNS_set_file:
-       //fprintf(stderr, "DW_LNS_set_file\n");
+         if (verbose) fprintf(stderr, "DW_LNS_set_file\n");
          lnd->cur.file = read_uleb128 (lnd);
          break;
        case DW_LNS_set_column:
-       //fprintf(stderr, "DW_LNS_set_column\n");
+         if (verbose) fprintf(stderr, "DW_LNS_set_column\n");
          lnd->cur.col = read_uleb128 (lnd);
          break;
        case DW_LNS_const_add_pc:
-       //fprintf(stderr, "DW_LNS_const_add_pc\n");
+         if (verbose) fprintf(stderr, "DW_LNS_const_add_pc\n");
          lnd->cur.pc += ((255 - lnd->opcode_base) / lnd->line_range
                          * lnd->minimum_instruction_length);
          break;
        case DW_LNS_fixed_advance_pc:
-       //fprintf(stderr, "DW_LNS_fixed_advance_pc\n");
+         if (verbose) fprintf(stderr, "DW_LNS_fixed_advance_pc\n");
          if (lnd->end - lnd->cpos < 2)
            return false;
          lnd->cur.pc += read_16 (lnd->cpos);
@@ -456,6 +465,7 @@ next_state (struct line_reader_data *lnd)
        default:
          {
            /* Don't know what it is, so skip it.  */
+           if (verbose) fprintf(stderr, "unknown opcode\n");
            int i;
            for (i = 0; i < lnd->standard_opcode_lengths[op - 1]; i++)
              skip_leb128 (lnd);
index 51d585ecb4b1a21c9c2d81af113fff5ae1b28416..e45c290d4242c4086fdcdb1eff64377de37d95e7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2006 Apple, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -20,6 +20,9 @@
  * 
  * @APPLE_LICENSE_HEADER_END@
  */
+#ifndef __DEBUG_LINE_H__
+#define __DEBUG_LINE_H__
+
 #include <stdint.h>
 #include <stddef.h>
 
@@ -107,3 +110,5 @@ void line_free (struct line_reader_data * lnd);
 }
 #endif
 
+#endif // __DEBUG_LINE_H__
+
index 115240e93b4745ae98e10f68c005e67f37f7850f..d9d66a679ab86b4e0ea3df0ec2c3e08b88a37cda 100644 (file)
@@ -1,5 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
- * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
+ *
+ * Copyright (c) 2005-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -23,7 +24,7 @@
  
 // start temp HACK for cross builds
 extern "C" double log2 ( double );
-#define __MATH__
+//#define __MATH__
 // end temp HACK for cross builds
 
 
@@ -36,11 +37,15 @@ extern "C" double log2 ( double );
 #include <errno.h>
 #include <limits.h>
 #include <unistd.h>
+#include <execinfo.h>
 #include <mach/mach_time.h>
 #include <mach/vm_statistics.h>
 #include <mach/mach_init.h>
 #include <mach/mach_host.h>
 #include <dlfcn.h>
+#include <mach-o/dyld.h>
+#include <dlfcn.h>
+#include <AvailabilityMacros.h>
 
 #include <string>
 #include <map>
@@ -50,848 +55,495 @@ extern "C" double log2 ( double );
 #include <list>
 #include <algorithm>
 #include <ext/hash_map>
-#include <dlfcn.h>
-#include <AvailabilityMacros.h>
+#include <ext/hash_set>
+#include <cxxabi.h>
 
-#include "configure.h"
 #include "Options.h"
 
-#include "ObjectFile.h"
-
-#include "MachOReaderRelocatable.hpp"
-#include "ArchiveReader.hpp"
-#include "MachOReaderDylib.hpp"
-#include "MachOWriterExecutable.hpp"
-
-#if LTO_SUPPORT
-#include "LTOReader.hpp"
-#endif
+#include "MachOFileAbstraction.hpp"
+#include "Architectures.hpp"
+#include "ld.hpp"
 
-#include "OpaqueSection.hpp"
+#include "InputFiles.h"
+#include "Resolver.h"
+#include "OutputFile.h"
 
+#include "passes/stubs/make_stubs.h"
+#include "passes/dtrace_dof.h"
+#include "passes/got.h"
+#include "passes/tlvp.h"
+#include "passes/huge.h"
+#include "passes/compact_unwind.h"
+#include "passes/order_file.h"
+#include "passes/branch_island.h"
+#include "passes/branch_shim.h"
+#include "passes/objc.h"
+#include "passes/dylibs.h"
 
-class CStringComparor
-{
-public:
-       bool operator()(const char* left, const char* right) const { return (strcmp(left, right) < 0); }
-};
+#include "parsers/archive_file.h"
+#include "parsers/macho_relocatable_file.h"
+#include "parsers/macho_dylib_file.h"
+#include "parsers/lto_file.h"
+#include "parsers/opaque_section_file.h"
 
-class CStringEquals
-{
-public:
-       bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
-};
 
-class Section : public ObjectFile::Section
+class InternalState : public ld::Internal
 {
 public:
-       static Section* find(const char* sectionName, const char* segmentName, bool zeroFill, bool untrustedZeroFill, bool createIfNeeded=true);
-       static void             assignIndexes(bool objfile);
-       const char*             getName() { return fSectionName; }
+                                                                                       InternalState(const Options& opts) : _options(opts) { }
+       virtual ld::Internal::FinalSection*             addAtom(const ld::Atom& atom);
+       virtual ld::Internal::FinalSection*             getFinalSection(const ld::Section&);
+       
+       void                                                                    sortSections();
+       virtual                                                                 ~InternalState() {}
 private:
-                                       Section(const char* sectionName, const char* segmentName, bool zeroFill, bool untrustedZeroFill);
 
-       struct Sorter {
-               static int      segmentOrdinal(const char* segName);
-               bool operator()(Section* left, Section* right);
+       class FinalSection : public ld::Internal::FinalSection 
+       {
+       public:
+                                                       FinalSection(const ld::Section& sect, uint32_t sectionsSeen, bool objFile);
+               static int                                      sectionComparer(const void* l, const void* r);
+               static const ld::Section&       outputSection(const ld::Section& sect);
+               static const ld::Section&       objectOutputSection(const ld::Section& sect, bool makeTentativeDefsReal);
+       private:
+               friend class InternalState;
+               static uint32_t         sectionOrder(const ld::Section& sect, uint32_t sectionsSeen);
+               static uint32_t         segmentOrder(const ld::Section& sect, bool objFile);
+               uint32_t                        _segmentOrder;
+               uint32_t                        _sectionOrder;
+
+               static std::vector<const char*> _s_segmentsSeen;
+               static ld::Section              _s_DATA_data;
+               static ld::Section              _s_DATA_const;
+               static ld::Section              _s_TEXT_text;
+               static ld::Section              _s_TEXT_const;
+               static ld::Section              _s_DATA_nl_symbol_ptr;
+               static ld::Section              _s_DATA_common;
        };
-
-       typedef __gnu_cxx::hash_map<const char*, uint32_t, __gnu_cxx::hash<const char*>, CStringEquals> NameToOrdinal;
-       typedef __gnu_cxx::hash_map<const char*, class Section*, __gnu_cxx::hash<const char*>, CStringEquals> NameToSection;
-       //typedef std::map<const char*, class Section*, CStringComparor> NameToSection;
-
-       char                    fSectionName[18];
-       char                    fSegmentName[18];
-       bool                    fZeroFill;
-       bool                    fUntrustedZeroFill;
-
-       static NameToSection                    fgMapping;
-       static std::vector<Section*>    fgSections;
-       static NameToOrdinal                    fgSegmentDiscoverOrder;
-       static bool                                             fgMakingObjectFile;
-};
-
-Section::NameToSection Section::fgMapping;
-std::vector<Section*>  Section::fgSections;
-Section::NameToOrdinal Section::fgSegmentDiscoverOrder;
-bool                                   Section::fgMakingObjectFile;
-
-Section::Section(const char* sectionName, const char* segmentName, bool zeroFill, bool untrustedZeroFill)
- : fZeroFill(zeroFill), fUntrustedZeroFill(untrustedZeroFill)
-{
-       strlcpy(fSectionName, sectionName, sizeof(fSectionName));
-       strlcpy(fSegmentName, segmentName, sizeof(fSegmentName));
-
-       this->fIndex = fgSections.size() + 20;  // room for 20 standard sections
-       // special placement of some sections
-       if ( strcmp(segmentName, "__TEXT") == 0 ) {
-               // sort mach header and load commands to start of TEXT
-               if ( strcmp(sectionName, "._mach_header") == 0 )
-                       this->fIndex = 1;
-               else if ( strcmp(sectionName, "._load_commands") == 0 ) 
-                       this->fIndex = 2;
-               else if ( strcmp(sectionName, "._load_cmds_pad") == 0 ) 
-                       this->fIndex = 3;
-               // sort __text after load commands
-               else if ( strcmp(sectionName, "__text") == 0 ) 
-                       this->fIndex = 10;
-               // sort arm/ppc stubs after text to make branch islands feasible
-               else if ( strcmp(sectionName, "__picsymbolstub4") == 0 ) 
-                       this->fIndex = 11;
-               else if ( strcmp(sectionName, "__symbol_stub4") == 0 ) 
-                       this->fIndex = 11;
-               else if ( strcmp(sectionName, "__picsymbolstub1") == 0 ) 
-                       this->fIndex = 11;
-               else if ( strcmp(sectionName, "__symbol_stub1") == 0 ) 
-                       this->fIndex = 11;
-               // sort fast arm stubs to end of __TEXT to be close to lazy pointers
-               else if ( strcmp(sectionName, "__symbolstub1") == 0 ) 
-                       this->fIndex = INT_MAX;  
-               // sort unwind info to end of segment
-               else if ( strcmp(sectionName, "__eh_frame") == 0 )
-                       this->fIndex = INT_MAX-1;
-               else if ( strcmp(sectionName, "__unwind_info") == 0 ) 
-                       this->fIndex = INT_MAX-2;
-               else if ( strcmp(sectionName, "__gcc_except_tab") == 0 ) 
-                       this->fIndex = INT_MAX-3;
-       }
-       else if ( strcmp(segmentName, "__DATA") == 0 ) {
-               // sort arm lazy symbol pointers that must be at start of __DATA
-               if ( strcmp(sectionName, "__lazy_symbol") == 0 ) 
-                       this->fIndex = 0;
-               // sort sections dyld will touch to start of segment
-               else if ( strcmp(sectionName, "__dyld") == 0 )
-                       this->fIndex = 1;
-               else if ( strcmp(sectionName, "__program_vars") == 0 ) 
-                       this->fIndex = 1;
-               else if ( strcmp(sectionName, "__mod_init_func") == 0 ) 
-                       this->fIndex = 2;
-               else if ( strcmp(sectionName, "__nl_symbol_ptr") == 0 ) 
-                       this->fIndex = 3;
-               else if ( strcmp(sectionName, "__la_symbol_ptr") == 0 ) 
-                       this->fIndex = 4;
-               else if ( strcmp(sectionName, "__const") == 0 ) 
-                       this->fIndex = 5;
-               else if ( strcmp(sectionName, "__cfstring") == 0 ) 
-                       this->fIndex = 6;
-               else if ( strcmp(sectionName, "__gcc_except_tab") == 0 ) 
-                       this->fIndex = 7;
-               else if ( strcmp(sectionName, "__objc_data") == 0 ) 
-                       this->fIndex = 8;
-               else if ( strcmp(sectionName, "__objc_msgrefs") == 0 ) 
-                       this->fIndex = 9;
-               else if ( strcmp(sectionName, "__objc_protorefs") == 0 ) 
-                       this->fIndex = 10;
-               else if ( strcmp(sectionName, "__objc_selrefs") == 0 ) 
-                       this->fIndex = 11;
-               else if ( strcmp(sectionName, "__objc_classrefs") == 0 ) 
-                       this->fIndex = 12;
-               else if ( strcmp(sectionName, "__objc_superrefs") == 0 ) 
-                       this->fIndex = 13;
-               else if ( strcmp(sectionName, "__objc_const") == 0 ) 
-                       this->fIndex = 14;
-               else if ( strcmp(sectionName, "__objc_classlist") == 0 ) 
-                       this->fIndex = 15;
-               else if ( strcmp(sectionName, "__objc_nlclslist") == 0 ) 
-                       this->fIndex = 16;
-               else if ( strcmp(sectionName, "__objc_catlist") == 0 ) 
-                       this->fIndex = 17;
-               else if ( strcmp(sectionName, "__objc_protolist") == 0 ) 
-                       this->fIndex = 18;
-               else if ( strcmp(sectionName, "__objc_imageinfo") == 0 ) 
-                       this->fIndex = 19;
-               else if ( strcmp(sectionName, "__huge") == 0 ) 
-                       this->fIndex = INT_MAX;
        
-       }
        
-       //fprintf(stderr, "new Section(%s, %s) => %p, %u\n", sectionName, segmentName, this, this->getIndex());
-}
-
-Section* Section::find(const char* sectionName, const char* segmentName, bool zeroFill, bool untrustedZeroFill, bool createIfNeeded)
-{
-       NameToSection::iterator pos = fgMapping.find(sectionName);
-       if ( pos != fgMapping.end() ) {
-               if ( strcmp(pos->second->fSegmentName, segmentName) == 0 ) {
-                       if ( !untrustedZeroFill && pos->second->fUntrustedZeroFill ) {
-                               pos->second->fZeroFill = zeroFill;
-                               pos->second->fUntrustedZeroFill = false;
-                       }
-                       return pos->second;
-               }
-               // otherwise same section name is used in different segments, look slow way
-               for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++) {
-                       if ( (strcmp((*it)->fSectionName, sectionName) == 0) && (strcmp((*it)->fSegmentName, segmentName) == 0) )
-                               return *it;
-               }
-       }
-
-       if ( !createIfNeeded ) 
-               return NULL;
+       struct SectionHash {
+               size_t operator()(const ld::Section*) const;
+       };
+       struct SectionEquals {
+               bool operator()(const ld::Section* left, const ld::Section* right) const;
+       };
+       typedef __gnu_cxx::hash_map<const ld::Section*, FinalSection*, SectionHash, SectionEquals> SectionInToOut;
        
-       // does not exist, so make a new one
-       Section* sect = new Section(sectionName, segmentName, zeroFill, untrustedZeroFill);
-       fgMapping[sectionName] = sect;
-       fgSections.push_back(sect);
 
-       if ( (strcmp(sectionName, "__text") == 0) && (strcmp(segmentName, "__TEXT") == 0) ) {
-               // special case __StaticInit to be right after __text
-               find("__StaticInit", "__TEXT", false, true);
-       }
+       SectionInToOut                  _sectionInToFinalMap;
+       const Options&                  _options;
+};
 
-       // remember segment discovery order
-       if ( fgSegmentDiscoverOrder.find(segmentName) == fgSegmentDiscoverOrder.end() ) 
-               fgSegmentDiscoverOrder[segmentName] = fgSegmentDiscoverOrder.size();
+ld::Section    InternalState::FinalSection::_s_DATA_data( "__DATA", "__data",  ld::Section::typeUnclassified);
+ld::Section    InternalState::FinalSection::_s_DATA_const("__DATA", "__const", ld::Section::typeUnclassified);
+ld::Section    InternalState::FinalSection::_s_TEXT_text( "__TEXT", "__text",  ld::Section::typeCode);
+ld::Section    InternalState::FinalSection::_s_TEXT_const("__TEXT", "__const", ld::Section::typeUnclassified);
+ld::Section    InternalState::FinalSection::_s_DATA_nl_symbol_ptr("__DATA", "__nl_symbol_ptr", ld::Section::typeNonLazyPointer);
+ld::Section    InternalState::FinalSection::_s_DATA_common("__DATA", "__common", ld::Section::typeZeroFill);
+std::vector<const char*> InternalState::FinalSection::_s_segmentsSeen;
 
-       return sect;
-}
 
-int Section::Sorter::segmentOrdinal(const char* segName)
+size_t InternalState::SectionHash::operator()(const ld::Section* sect) const
 {
-       if ( strcmp(segName, "__HEADER") == 0 )
-               return 1;
-       if ( strcmp(segName, "__PAGEZERO") == 0 )
-               return 1;
-       if ( strcmp(segName, "__TEXT") == 0 )
-               return 2;
-       if ( strcmp(segName, "__DATA") == 0 )
-               return (fgMakingObjectFile ? 6 : 3); // __DATA is last in .o files and here in FLI
-       if ( strcmp(segName, "__OBJC") == 0 )
-               return 4;
-       if ( strcmp(segName, "__IMPORT") == 0 )
-               return 5;
-       if ( strcmp(segName, "__LINKEDIT") == 0 )
-               return INT_MAX; // linkedit segment should always sort last
-       else
-               return fgSegmentDiscoverOrder[segName]+6;
+       size_t hash = 0;        
+       __gnu_cxx::hash<const char*> temp;
+       hash += temp.operator()(sect->segmentName());
+       hash += temp.operator()(sect->sectionName());
+       return hash;
 }
 
-
-bool Section::Sorter::operator()(Section* left, Section* right)
+bool InternalState::SectionEquals::operator()(const ld::Section* left, const ld::Section* right) const
 {
-       // Segment is primary sort key
-       int leftSegOrdinal = segmentOrdinal(left->fSegmentName);
-       int rightSegOrdinal = segmentOrdinal(right->fSegmentName);
-       if ( leftSegOrdinal < rightSegOrdinal )
-               return true;
-       if ( leftSegOrdinal > rightSegOrdinal )
-               return false;
-
-       // zerofill section sort to the end
-       if ( !left->fZeroFill && right->fZeroFill )
-               return true;
-       if ( left->fZeroFill && !right->fZeroFill )
-               return false;
-
-       // section discovery order is last sort key
-       return left->fIndex < right->fIndex;
+       return (*left == *right);
 }
 
-void Section::assignIndexes(bool objfile)
-{      
-       //printf("unsorted sections:\n");
-       //for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++) {
-       //      printf("section: name=%s, segment: name=%s, discovery order=%d\n", (*it)->fSectionName, (*it)->fSegmentName, (*it)->fIndex);
-       //}
-
-       // sort it
-       Section::fgMakingObjectFile = objfile;
-       std::sort(fgSections.begin(), fgSections.end(), Section::Sorter());
 
-       // assign correct section ordering to each Section object
-       unsigned int newOrder = 1;
-       for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++)
-               (*it)->fIndex = newOrder++;
-
-       //printf("sorted sections:\n");
-       //for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++) {
-       //      printf("section: index=%d, obj=%p, name=%s\n", (*it)->fIndex, (*it), (*it)->fSectionName);
-       //}
+InternalState::FinalSection::FinalSection(const ld::Section& sect, uint32_t sectionsSeen, bool objFile)
+       : ld::Internal::FinalSection(sect), 
+         _segmentOrder(segmentOrder(sect, objFile)),
+         _sectionOrder(sectionOrder(sect, sectionsSeen))
+{
+       //fprintf(stderr, "FinalSection(%s, %s) _segmentOrder=%d, _sectionOrder=%d\n", 
+       //              this->segmentName(), this->sectionName(), _segmentOrder, _sectionOrder);
 }
 
-class Linker : public ObjectFile::Reader::DylibHander {
-public:
-                                               Linker(int argc, const char* argv[]);
-
-       const char*                     getArchPrefix();
-       const char*                     architectureName();
-       bool                            showArchitectureInErrors();
-       bool                            isInferredArchitecture();
-       void                            createReaders();
-       void                            createWriter();
-       void                            addInputFile(ObjectFile::Reader* reader, const Options::FileInfo& );
-       void                            setOutputFile(ExecutableFile::Writer* writer);
-       void                            link();
-       void                            optimize();
-       
-       // implemenation from ObjectFile::Reader::DylibHander
-       virtual ObjectFile::Reader* findDylib(const char* installPath, const char* fromPath);
-
-private:
-       struct WhyLiveBackChain
-       {
-               WhyLiveBackChain*       previous;
-               ObjectFile::Atom*       referer;
-       };
-
-       ObjectFile::Reader*     createReader(const Options::FileInfo&);
-       const char*                     fileArch(const void* p);
-       void                            addAtom(ObjectFile::Atom& atom);
-       void                            addAtoms(std::vector<class ObjectFile::Atom*>& atoms);
-       void                            buildAtomList();
-       void                            adjustScope();
-       void                            processDylibs();
-       void                            markDead(ObjectFile::Atom* atom);
-       void                            updateConstraints(ObjectFile::Reader* reader);
-       void                            loadAndResolve();
-       void                            processDTrace();
-       void                            checkObjC();
-       void                            addSynthesizedAtoms();
-       void                            loadUndefines();
-       void                            checkUndefines();
-       void                            resolveReferences();
-       void                            deadStripResolve();
-       void                            addLiveRoot(const char* name);
-       void                            moveToFrontOfSection(ObjectFile::Atom* atom);
-       ObjectFile::Atom*       findAtom(const Options::OrderedSymbol& pair);
-       void                            logArchive(ObjectFile::Reader* reader);
-       void                            sortSections();
-       void                            sortAtoms();
-       void                            tweakLayout();
-       void                            writeDotOutput();
-       static bool                     minimizeStab(ObjectFile::Reader::Stab& stab);
-       static const char*      truncateStabString(const char* str);
-       void                            collectDebugInfo();
-       void                            writeOutput();
-       ObjectFile::Atom*       entryPoint(bool orInit, bool searchArchives=false);
-       ObjectFile::Atom*       dyldClassicHelper();
-       ObjectFile::Atom*       dyldCompressedHelper();
-       ObjectFile::Atom*       dyldLazyLibraryHelper();
-       const char*                     assureFullPath(const char* path);
-       void                            markLive(ObjectFile::Atom& atom, Linker::WhyLiveBackChain* previous);
-       void                            collectStabs(ObjectFile::Reader* reader, std::map<const class ObjectFile::Atom*, uint32_t>& atomOrdinals);
-       void                            synthesizeDebugNotes(std::vector<class ObjectFile::Atom*>& allAtomsByReader);
-       void                            printStatistics();
-       void                            printTime(const char* msg, uint64_t partTime, uint64_t totalTime);
-       char*                           commatize(uint64_t in, char* out);
-       void                            getVMInfo(vm_statistics_data_t& info);
-       cpu_type_t                      inferArchitecture();
-       void                            checkDylibClientRestrictions(ObjectFile::Reader* reader);
-       void                            logDylib(ObjectFile::Reader* reader, bool indirect);
-       
-       void                                                                    resolve(ObjectFile::Reference* reference);
-       void                                                                    resolveFrom(ObjectFile::Reference* reference);
-       std::vector<class ObjectFile::Atom*>*   addJustInTimeAtoms(const char* name, bool searchDylibs, bool searchArchives, bool okToMakeProxy);
-       void                                                                    addJustInTimeAtomsAndMarkLive(const char* name);
-
-       ObjectFile::Reader*     addDylib(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen);
-       ObjectFile::Reader*     addObject(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen);
-       ObjectFile::Reader*     addArchive(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen);
-
-       void                            logTraceInfo(const char* format, ...);
-
-
-       class SymbolTable
-       {
-       public:
-               typedef __gnu_cxx::hash_map<const char*, ObjectFile::Atom*, __gnu_cxx::hash<const char*>, CStringEquals> Mapper;
-
-                                                       SymbolTable(Linker&);
-               void                            require(const char* name);
-               bool                            add(ObjectFile::Atom& atom);
-               ObjectFile::Atom*       find(const char* name);
-               void                            erase(const char* name);
-               unsigned int            getRequireCount() { return fRequireCount; }
-               void                            getUndefinesNames(std::vector<const char*>& undefines);
-               void                            getTentativesNames(std::vector<const char*>& tents);
-               bool                            hasExternalTentativeDefinitions() { return fHasExternalTentativeDefinitions; }
-               bool                            hasExternalWeakDefinitions() { return fHasExternalWeakDefinitions; }
-               void                            setHasExternalWeakDefinitions(bool value) { fHasExternalWeakDefinitions = value; }
-               uint32_t                        dylibSymbolCount() { return fDylibSymbolCount; }
-               Mapper::iterator        begin() { return fTable.begin(); }
-               Mapper::iterator        end()   { return fTable.end(); }
-
-       private:
-               Linker&                         fOwner;
-               Mapper                          fTable;
-               unsigned int            fRequireCount;
-               bool                            fHasExternalTentativeDefinitions;
-               bool                            fHasExternalWeakDefinitions;
-               uint32_t                        fDylibSymbolCount;
-       };
-
-       class AtomSorter
-       {
-       public:
-               AtomSorter(std::map<const ObjectFile::Atom*, uint32_t>* map, std::set<const ObjectFile::Atom*>& inits, 
-                                                       std::set<const ObjectFile::Atom*>& terms) : 
-                               fOverriddenOrdinalMap(map), fInitializerSet(inits), fTerminatorSet(terms) {}
-               bool operator()(const ObjectFile::Atom* left, const ObjectFile::Atom* right);
-       private:
-               std::map<const ObjectFile::Atom*, uint32_t>*    fOverriddenOrdinalMap;
-               std::set<const ObjectFile::Atom*>&                              fInitializerSet;
-               std::set<const ObjectFile::Atom*>&                              fTerminatorSet;
-       };
-
-       typedef std::map<const char*, uint32_t, CStringComparor> SectionOrder;
-
-       struct DTraceProbeInfo {
-               DTraceProbeInfo(const ObjectFile::Atom* a, uint32_t o, const char* n) : atom(a), offset(o), probeName(n) {}
-               const ObjectFile::Atom*                 atom;
-               uint32_t                                                offset;
-               const char*                                             probeName;
-       };
-       typedef __gnu_cxx::hash_map<const char*, std::vector<DTraceProbeInfo>, __gnu_cxx::hash<const char*>, CStringEquals>     ProviderToProbes;
-       typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals>  CStringSet;
-       typedef __gnu_cxx::hash_map<const char*, ObjectFile::Reader*, __gnu_cxx::hash<const char*>, CStringEquals>      InstallNameToReader;
-
-       struct IndirectLibrary {
-               const char*                                                     path;
-               uint64_t                                                        fileLen;
-               ObjectFile::Reader*                                     reader;
-               std::set<ObjectFile::Reader*>           parents;
-               ObjectFile::Reader*                                     reExportedViaDirectLibrary;
-       };
-
-       ObjectFile::Reader* findDirectLibraryWhichReExports(struct IndirectLibrary& indirectLib);
-
-       Options                                                                                         fOptions;
-       SymbolTable                                                                                     fGlobalSymbolTable;
-       uint32_t                                                                                        fNextInputOrdinal;
-       std::vector<class ObjectFile::Reader*>                          fInputFiles;
-       ExecutableFile::Writer*                                                         fOutputFile;
-       InstallNameToReader                                                                     fDylibMap;
-       std::map<ObjectFile::Reader*,LibraryOptions>            fDylibOptionsMap;
-       std::set<ObjectFile::Reader*>                                           fDylibsProcessed;
-       ObjectFile::Reader*                                                                     fBundleLoaderReader;
-       std::vector<class ObjectFile::Reader*>                          fReadersThatHaveSuppliedAtoms;
-       std::vector<class ObjectFile::Atom*>                            fAllAtoms;
-       std::set<class ObjectFile::Reader*>                                     fArchiveReaders;
-       std::set<class ObjectFile::Reader*>                                     fArchiveReadersLogged;
-       std::set<class ObjectFile::Atom*>                                       fDeadAtoms;
-       std::set<ObjectFile::Atom*>                                                     fLiveAtoms;
-       std::set<ObjectFile::Atom*>                                                     fLiveRootAtoms;
-       std::set<const ObjectFile::Atom*>                                       fInitializerAtoms;
-       std::set<const ObjectFile::Atom*>                                       fTerminatorAtoms;
-       std::set<const ObjectFile::Atom*>                                       fRegularDefAtomsThatOverrideADylibsWeakDef;
-       std::vector<class ObjectFile::Reader::Stab>                     fStabs;
-       std::vector<class ObjectFile::Atom*>                            fAtomsWithUnresolvedReferences;
-       std::set<class ObjectFile::Atom*>                                       fAtomsOverriddenByLateLoads;
-       bool                                                                                            fInitialLoadsDone;
-       bool                                                                                            fCreateUUID;
-       bool                                                                                            fCanScatter;
-       SectionOrder                                                                            fSectionOrder;
-       cpu_type_t                                                                                      fArchitecture;
-       const char*                                                                                     fArchitectureName;
-       bool                                                                                            fArchitectureInferred;
-       bool                                                                                            fDirectLibrariesComplete;
-       bool                                                                                            fBiggerThanTwoGigOutput;
-       uint64_t                                                                                        fOutputFileSize;
-       uint64_t                                                                                        fTotalZeroFillSize;
-       uint64_t                                                                                        fTotalSize;
-       uint64_t                                                                                        fStartTime;
-       uint64_t                                                                                        fStartCreateReadersTime;
-       uint64_t                                                                                        fStartCreateWriterTime;
-       uint64_t                                                                                        fStartBuildAtomsTime;
-       uint64_t                                                                                        fStartLoadAndResolveTime;
-       uint64_t                                                                                        fStartSortTime;
-       uint64_t                                                                                        fStartDebugTime;
-       uint64_t                                                                                        fStartWriteTime;
-       uint64_t                                                                                        fEndTime;
-       uint64_t                                                                                        fTotalObjectSize;
-       uint64_t                                                                                        fTotalArchiveSize;
-       uint32_t                                                                                        fTotalObjectLoaded;
-       uint32_t                                                                                        fTotalArchivesLoaded;
-       uint32_t                                                                                        fTotalDylibsLoaded;
-       vm_statistics_data_t                                                            fStartVMInfo;
-       ObjectFile::Reader::ObjcConstraint                                      fCurrentObjCConstraint;
-       ObjectFile::Reader::CpuConstraint                                       fCurrentCpuConstraint;
-       bool                                                                                            fObjcReplacmentClasses;
-       bool                                                                                            fAllDirectDylibsLoaded;
-};
-
-
-Linker::Linker(int argc, const char* argv[])
-       : fOptions(argc, argv), fGlobalSymbolTable(*this), fNextInputOrdinal(1), fOutputFile(NULL), fBundleLoaderReader(NULL), 
-         fInitialLoadsDone(false), fCreateUUID(fOptions.outputKind() != Options::kObjectFile), fCanScatter(true),
-         fArchitecture(0), fArchitectureInferred(false), fDirectLibrariesComplete(false), fBiggerThanTwoGigOutput(false),
-         fOutputFileSize(0), fTotalZeroFillSize(0), fTotalSize(0), fTotalObjectSize(0),
-         fTotalArchiveSize(0),  fTotalObjectLoaded(0), fTotalArchivesLoaded(0), fTotalDylibsLoaded(0),
-         fCurrentObjCConstraint(ObjectFile::Reader::kObjcNone), fCurrentCpuConstraint(ObjectFile::Reader::kCpuAny),
-         fObjcReplacmentClasses(false), fAllDirectDylibsLoaded(false)
+const ld::Section& InternalState::FinalSection::outputSection(const ld::Section& sect)
 {
-       fStartTime = mach_absolute_time();
-       if ( fOptions.printStatistics() )
-               getVMInfo(fStartVMInfo);
-
-       fArchitecture = fOptions.architecture();
-       if ( fArchitecture == 0 ) {
-               // -arch not specified, scan .o files to figure out what it should be
-               fArchitecture = inferArchitecture();
-               fArchitectureInferred = true;
-       }
-       switch (fArchitecture) {
-               case CPU_TYPE_POWERPC:
-                       fArchitectureName = "ppc";
-                       break;
-               case CPU_TYPE_POWERPC64:
-                       fArchitectureName = "ppc64";
-                       break;
-               case CPU_TYPE_I386:
-                       fArchitectureName = "i386";
+       // merge sections in final linked image
+       switch ( sect.type() ) {
+               case ld::Section::typeLiteral4:
+               case ld::Section::typeLiteral8:
+               case ld::Section::typeLiteral16:
+                       return _s_TEXT_const;
+               case ld::Section::typeUnclassified:
+                       if ( strcmp(sect.segmentName(), "__DATA") == 0 ) {
+                               if ( strcmp(sect.sectionName(), "__datacoal_nt") == 0 )
+                                       return _s_DATA_data;
+                               if ( strcmp(sect.sectionName(), "__const_coal") == 0 )
+                                       return _s_DATA_const;
+                       }
+                       else if ( strcmp(sect.segmentName(), "__TEXT") == 0 ) {
+                               if ( strcmp(sect.sectionName(), "__const_coal") == 0 )
+                                       return _s_TEXT_const;
+                       }
                        break;
-               case CPU_TYPE_X86_64:
-                       fArchitectureName = "x86_64";
+               case ld::Section::typeCode:
+                       if ( strcmp(sect.segmentName(), "__TEXT") == 0 ) {
+                               if ( strcmp(sect.sectionName(), "__textcoal_nt") == 0 )
+                                       return _s_TEXT_text;
+                               else if ( strcmp(sect.sectionName(), "__StaticInit") == 0 )
+                                       return _s_TEXT_text;
+                       }
                        break;
-               case CPU_TYPE_ARM:
-                       fArchitectureName = "arm";
-                       if ( fOptions.preferSubArchitecture() ) {
-                               switch ( fOptions.subArchitecture() ) {
-                                       case CPU_SUBTYPE_ARM_V4T:
-                                               fArchitectureName = "armv4t";
-                                               break;
-                                       case CPU_SUBTYPE_ARM_V5TEJ:
-                                               fArchitectureName = "armv5";
-                                               break;
-                                       case CPU_SUBTYPE_ARM_V6:
-                                               fArchitectureName = "armv6";
-                                               break;
-                                       case CPU_SUBTYPE_ARM_V7:
-                                               fArchitectureName = "armv7";
-                                               break;
-                               }
+               case ld::Section::typeNonLazyPointer:
+                       if ( strcmp(sect.segmentName(), "__DATA") == 0 ) {
+                               if ( strcmp(sect.sectionName(), "__nl_symbol_ptr") == 0 )
+                                       return _s_DATA_nl_symbol_ptr;
+                       }
+                       else if ( strcmp(sect.segmentName(), "__IMPORT") == 0 ) {
+                               if ( strcmp(sect.sectionName(), "__pointers") == 0 )
+                                       return _s_DATA_nl_symbol_ptr; 
                        }
                        break;
+               case ld::Section::typeTentativeDefs:
+                       return _s_DATA_common;
+                       break;
+                       // FIX ME: more 
                default:
-                       fArchitectureName = "unknown architecture";
                        break;
        }
+       return sect;
 }
 
-const char*    Linker::architectureName()
-{
-       return fArchitectureName;
-}
-
-bool Linker::showArchitectureInErrors()
+const ld::Section& InternalState::FinalSection::objectOutputSection(const ld::Section& sect, bool makeTentativeDefsReal)
 {
-       return fOptions.printArchPrefix();
+       // in -r mode the only section that ever changes is __tenative -> __common with -d option
+       if ( (sect.type() == ld::Section::typeTentativeDefs) && makeTentativeDefsReal)
+               return _s_DATA_common;
+       return sect;
 }
 
-bool Linker::isInferredArchitecture()
+uint32_t InternalState::FinalSection::segmentOrder(const ld::Section& sect, bool objFile)
 {
-       return fArchitectureInferred;
+       if ( strcmp(sect.segmentName(), "__PAGEZERO") == 0 ) 
+               return 0;
+       if ( strcmp(sect.segmentName(), "__HEADER") == 0 ) // only used with -preload
+               return 0;
+       if ( strcmp(sect.segmentName(), "__TEXT") == 0 ) 
+               return 1;
+       // in -r mode, want __DATA  last so zerofill sections are at end
+       if ( strcmp(sect.segmentName(), "__DATA") == 0 ) 
+               return (objFile ? 5 : 2);
+       if ( strcmp(sect.segmentName(), "__OBJC") == 0 ) 
+               return 3;
+       if ( strcmp(sect.segmentName(), "__IMPORT") == 0 ) 
+               return 4;
+       
+       // layout non-standard segments in order seen (+10 to shift beyond standard segments)
+       for (uint32_t i=0; i < _s_segmentsSeen.size(); ++i) {
+               if ( strcmp(_s_segmentsSeen[i], sect.segmentName()) == 0 )
+                       return i+10;
+       }
+       _s_segmentsSeen.push_back(sect.segmentName());
+       return _s_segmentsSeen.size()-1+10;
 }
 
-cpu_type_t Linker::inferArchitecture()
+uint32_t InternalState::FinalSection::sectionOrder(const ld::Section& sect, uint32_t sectionsSeen)
 {
-       // scan all input files, looking for a thin .o file.
-       // the first one found is presumably the architecture to link
-       uint8_t buffer[sizeof(mach_header_64)];
-       std::vector<Options::FileInfo>& files = fOptions.getInputFiles();
-       for (std::vector<Options::FileInfo>::iterator it = files.begin(); it != files.end(); ++it) {
-               int fd = ::open(it->path, O_RDONLY, 0);
-               if ( fd != -1 ) {
-                       ssize_t amount = read(fd, buffer, sizeof(buffer));
-                       ::close(fd);
-                       if ( amount >= (ssize_t)sizeof(buffer) ) {
-                               if ( mach_o::relocatable::Reader<ppc>::validFile(buffer) ) {
-                                       //warning("-arch not used, infering -arch ppc based on %s", it->path);
-                                       return CPU_TYPE_POWERPC;
-                               }
-                               else if ( mach_o::relocatable::Reader<ppc64>::validFile(buffer) ) {
-                                       //warning("-arch not used, infering -arch ppc64 based on %s", it->path);
-                                       return CPU_TYPE_POWERPC64;
-                               }
-                               else if ( mach_o::relocatable::Reader<x86>::validFile(buffer) ) {
-                                       //warning("-arch not used, infering -arch i386 based on %s", it->path);
-                                       return CPU_TYPE_I386;
-                               }
-                               else if ( mach_o::relocatable::Reader<x86_64>::validFile(buffer) ) {
-                                       //warning("-arch not used, infering -arch x86_64 based on %s", it->path);
-                                       return CPU_TYPE_X86_64;
-                               }
-                               else if ( mach_o::relocatable::Reader<arm>::validFile(buffer) ) {
-                                       //warning("-arch not used, infering -arch arm based on %s", it->path);
-                                       return CPU_TYPE_ARM;
-                               }
+       if ( sect.type() == ld::Section::typeFirstSection )
+               return 0;
+       if ( sect.type() == ld::Section::typeMachHeader )
+               return 1;
+       if ( sect.type() == ld::Section::typeLastSection )
+               return INT_MAX;
+       if ( strcmp(sect.segmentName(), "__TEXT") == 0 ) {
+               switch ( sect.type() ) {
+                       case ld::Section::typeCode:
+                               // <rdar://problem/8346444> make __text always be first "code" section
+                               if ( strcmp(sect.sectionName(), "__text") == 0 )
+                                       return 10;
+                               else
+                                       return 11;
+                       case ld::Section::typeStub:
+                               return 12;
+                       case ld::Section::typeStubHelper:
+                               return 13;
+                       case ld::Section::typeLSDA:
+                               return INT_MAX-3;
+                       case ld::Section::typeUnwindInfo:
+                               return INT_MAX-2;
+                       case ld::Section::typeCFI:
+                               return INT_MAX-1;
+                       case ld::Section::typeStubClose:
+                               return INT_MAX;
+                       default:
+                               return sectionsSeen+20;
+               }
+       }
+       else if ( strcmp(sect.segmentName(), "__DATA") == 0 ) {
+               switch ( sect.type() ) {
+                       case ld::Section::typeLazyPointerClose:
+                               return 8;
+                       case ld::Section::typeDyldInfo:
+                               return 9;
+                       case ld::Section::typeNonLazyPointer:
+                               return 10;
+                       case ld::Section::typeLazyPointer:
+                               return 11;
+                       case ld::Section::typeInitializerPointers:
+                               return 12;
+                       case ld::Section::typeTerminatorPointers:
+                               return 13;
+                       case ld::Section::typeTLVInitialValues:
+                               return INT_MAX-4; // need TLV zero-fill to follow TLV init values
+                       case ld::Section::typeTLVZeroFill:
+                               return INT_MAX-3;
+                       case ld::Section::typeZeroFill:
+                               // make sure __huge is always last zerofill section
+                               if ( strcmp(sect.sectionName(), "__huge") == 0 )
+                                       return INT_MAX-1;
+                               else
+                                       return INT_MAX-2;
+                       default:
+                               // <rdar://problem/7435296> Reorder sections to reduce page faults in object files
+                               if ( strcmp(sect.sectionName(), "__objc_classlist") == 0 ) 
+                                       return 20;
+                               else if ( strcmp(sect.sectionName(), "__objc_nlclslist") == 0 ) 
+                                       return 21;
+                               else if ( strcmp(sect.sectionName(), "__objc_catlist") == 0 ) 
+                                       return 22;
+                               else if ( strcmp(sect.sectionName(), "__objc_protolist") == 0 ) 
+                                       return 23;
+                               else if ( strcmp(sect.sectionName(), "__objc_imageinfo") == 0 ) 
+                                       return 24;
+                               else if ( strcmp(sect.sectionName(), "__objc_const") == 0 ) 
+                                       return 25;
+                               else if ( strcmp(sect.sectionName(), "__objc_selrefs") == 0 ) 
+                                       return 26;
+                               else if ( strcmp(sect.sectionName(), "__objc_msgrefs") == 0 ) 
+                                       return 27;
+                               else if ( strcmp(sect.sectionName(), "__objc_protorefs") == 0 ) 
+                                       return 28;
+                               else if ( strcmp(sect.sectionName(), "__objc_classrefs") == 0 ) 
+                                       return 29;
+                               else if ( strcmp(sect.sectionName(), "__objc_superrefs") == 0 ) 
+                                       return 30;
+                               else if ( strcmp(sect.sectionName(), "__objc_data") == 0 ) 
+                                       return 31;
+                               else
+                                       return sectionsSeen+40;
+               }
+       }
+       // make sure zerofill in any other section is at end of segment
+       if ( sect.type() == ld::Section::typeZeroFill )
+               return INT_MAX-1;
+       return sectionsSeen+20;
+}
+
+#ifndef NDEBUG
+static void validateFixups(const ld::Atom& atom)
+{
+       //fprintf(stderr, "validateFixups %s\n", atom.name());
+       bool lastWasClusterEnd = true;
+       ld::Fixup::Cluster lastClusterSize = ld::Fixup::k1of1;
+       uint32_t curClusterOffsetInAtom = 0;
+       for (ld::Fixup::iterator fit=atom.fixupsBegin(); fit != atom.fixupsEnd(); ++fit) {
+               //fprintf(stderr, "  fixup offset=%d, cluster=%d\n", fit->offsetInAtom, fit->clusterSize);
+               assert((fit->offsetInAtom < atom.size()) || (fit->offsetInAtom == 0));
+               if ( fit->firstInCluster() ) {
+                       assert(lastWasClusterEnd);
+                       curClusterOffsetInAtom = fit->offsetInAtom;
+                       lastWasClusterEnd = (fit->clusterSize == ld::Fixup::k1of1);
+               }
+               else {
+                       assert(!lastWasClusterEnd);
+                       assert(fit->offsetInAtom == curClusterOffsetInAtom);
+                       switch ((ld::Fixup::Cluster)fit->clusterSize) {
+                               case ld::Fixup::k1of1:
+                               case ld::Fixup::k1of2:
+                               case ld::Fixup::k1of3:
+                               case ld::Fixup::k1of4:
+                               case ld::Fixup::k1of5:
+                                       lastWasClusterEnd = false;
+                                       break;
+                               case ld::Fixup::k2of2:
+                                       assert(lastClusterSize = ld::Fixup::k1of2);
+                                       lastWasClusterEnd = true;
+                                       break;
+                               case ld::Fixup::k2of3:
+                                       assert(lastClusterSize = ld::Fixup::k1of3);
+                                       lastWasClusterEnd = false;
+                                       break;
+                               case ld::Fixup::k2of4:
+                                       assert(lastClusterSize = ld::Fixup::k1of4);
+                                       lastWasClusterEnd = false;
+                                       break;
+                               case ld::Fixup::k2of5:
+                                       assert(lastClusterSize = ld::Fixup::k1of5);
+                                       lastWasClusterEnd = false;
+                                       break;
+                               case ld::Fixup::k3of3:
+                                       assert(lastClusterSize = ld::Fixup::k2of3);
+                                       lastWasClusterEnd = true;
+                                       break;
+                               case ld::Fixup::k3of4:
+                                       assert(lastClusterSize = ld::Fixup::k2of4);
+                                       lastWasClusterEnd = false;
+                                       break;
+                               case ld::Fixup::k3of5:
+                                       assert(lastClusterSize = ld::Fixup::k2of5);
+                                       lastWasClusterEnd = false;
+                                       break;
+                               case ld::Fixup::k4of4:
+                                       assert(lastClusterSize = ld::Fixup::k3of4);
+                                       lastWasClusterEnd = true;
+                                       break;
+                               case ld::Fixup::k4of5:
+                                       assert(lastClusterSize = ld::Fixup::k3of5);
+                                       lastWasClusterEnd = false;
+                                       break;
+                               case ld::Fixup::k5of5:
+                                       assert(lastClusterSize = ld::Fixup::k4of5);
+                                       lastWasClusterEnd = true;
+                                       break;
                        }
                }
+               lastClusterSize = fit->clusterSize;
+               if ( fit->binding == ld::Fixup::bindingDirectlyBound ) {
+                       assert(fit->u.target != NULL);
+               }
        }
-
-       // no thin .o files found, so default to same architecture this was built as
-       warning("-arch not specified");
-#if __ppc__
-       return CPU_TYPE_POWERPC;
-#elif __i386__
-       return CPU_TYPE_I386;
-#elif __ppc64__
-       return CPU_TYPE_POWERPC64;
-#elif __x86_64__
-       return CPU_TYPE_X86_64;
-#elif __arm__
-       return CPU_TYPE_ARM;
-#else
-       #error unknown default architecture
-#endif
-}
-
-
-void Linker::addInputFile(ObjectFile::Reader* reader, const Options::FileInfo& info)
-{
-       fInputFiles.push_back(reader);
-       fDylibOptionsMap[reader] = info.options;
-}
-
-void Linker::setOutputFile(ExecutableFile::Writer* writer)
-{
-       fOutputFile = writer;
-}
-
-class InSet
-{
-public:
-       InSet(std::set<ObjectFile::Atom*>& deadAtoms) : fDeadAtoms(deadAtoms) {}
-
-       bool operator()(ObjectFile::Atom*& atom) const {
-               return ( fDeadAtoms.count(atom) != 0 );
-       }
-
-private:
-       std::set<ObjectFile::Atom*>& fDeadAtoms;
-};
-
-void Linker::loadAndResolve()
-{
-       fStartLoadAndResolveTime = mach_absolute_time();
-       if ( fOptions.deadStrip() == Options::kDeadStripOff ) {
-               // without dead-code-stripping:
-               // find atoms to resolve all undefines
-               this->loadUndefines();
-               // verify nothing is missing
-               this->checkUndefines();
-               // once all undefines fulfill, then bind all references
-               this->resolveReferences();
-               // remove atoms weak atoms that have been overridden
-               fAllAtoms.erase(std::remove_if(fAllAtoms.begin(), fAllAtoms.end(), InSet(fDeadAtoms)), fAllAtoms.end());
-       }
-       else {
-               // with dead code stripping:
-               // start binding references from roots,
-               this->deadStripResolve();
-               // verify nothing is missing
-               this->checkUndefines();
+       switch (lastClusterSize) {
+               case ld::Fixup::k1of1:
+               case ld::Fixup::k2of2:
+               case ld::Fixup::k3of3:
+               case ld::Fixup::k4of4:
+               case ld::Fixup::k5of5:
+                       break;
+               default:
+                       assert(0 && "last fixup was not end of cluster");
+                       break;
        }
 }
+#endif
 
-void Linker::addSynthesizedAtoms()
-{
-       // give write a chance to synthesize stub, GOT, and lazy pointer atoms
-       std::vector<class ObjectFile::Atom*> newAtoms;
-       fOutputFile->addSynthesizedAtoms(fAllAtoms, this->dyldClassicHelper(), 
-                                                                       this->dyldCompressedHelper(), this->dyldLazyLibraryHelper(),
-                                                                       fBiggerThanTwoGigOutput,
-                                                                       fGlobalSymbolTable.dylibSymbolCount(),
-                                                                       newAtoms);
-
-       // add all newly created atoms to fAllAtoms and update symbol table
-       this->addAtoms(newAtoms);
-}
-
-void Linker::optimize()
-{
-       // give each reader a chance to do any optimizations
-       bool didSomething = false;
-       std::vector<class ObjectFile::Atom*> newAtoms;
-       std::vector<const char *> additionalUndefines;
-       std::vector<class ObjectFile::Atom*> newlyDeadAtoms;
-       for (std::vector<class ObjectFile::Reader*>::iterator it=fInputFiles.begin(); it != fInputFiles.end(); it++) {
-               didSomething |= (*it)->optimize(fAllAtoms, newAtoms, additionalUndefines, fDeadAtoms, newlyDeadAtoms, fNextInputOrdinal, 
-                       fOutputFile, entryPoint(true), fOptions.llvmOptions(),
-                        fOptions.allGlobalsAreDeadStripRoots(), (int)fOptions.outputKind(), fOptions.verbose(),
-                       fOptions.saveTempFiles(), fOptions.getOutputFilePath(), fOptions.positionIndependentExecutable(),
-                       fOptions.allowTextRelocs());
-       }
-       
-       // only do next steps if some optimization was actually done
-       if  ( didSomething ) {
-       
-               if ( fOptions.deadStrip() != Options::kDeadStripOff ) {
-                       for(std::vector<class ObjectFile::Atom*>::iterator itr = newAtoms.begin(); itr != newAtoms.end(); ++itr) {
-                               ObjectFile::Atom* atom = *itr;
-                               const char* name = atom->getName();
-                               if ( name != NULL ) {
-                                       ObjectFile::Atom* existingAtom = fGlobalSymbolTable.find(name);
-                                       if ( (existingAtom != NULL) && fLiveAtoms.count(existingAtom) == 0 ) {
-                                               // While dead code stripping, the atoms were not removed from fGlobalSymbolTable
-                                               // for performance reasons. Normally, libLTO will never recreate an atom
-                                               // that was previously dead stripped away, but if it does remove
-                                               // the remnents of the previous so the new one can be added
-                                               fGlobalSymbolTable.erase(name);
+ld::Internal::FinalSection* InternalState::addAtom(const ld::Atom& atom)
+{
+       ld::Internal::FinalSection* fs = this->getFinalSection(atom.section());
+
+       // <rdar://problem/8612550> When order file used on data, turn ordered zero fill symbols into zero data
+       switch ( atom.section().type() ) {
+               case ld::Section::typeZeroFill:
+               case ld::Section::typeTentativeDefs:
+                       if ( (_options.outputKind() == Options::kDyld) && (atom.symbolTableInclusion() == ld::Atom::symbolTableIn) 
+                                       && (atom.size() <= 512) && (_options.orderedSymbolsCount() != 0) ) {
+                               for(Options::OrderedSymbolsIterator it = _options.orderedSymbolsBegin(); it != _options.orderedSymbolsEnd(); ++it) {
+                                       if ( (it->objectFileName == NULL) && (strcmp(it->symbolName, atom.name()) == 0) ) {
+                                               // found in order file, move to __data section
+                                               fs = getFinalSection(InternalState::FinalSection::_s_DATA_data);\
+                                               //fprintf(stderr, "moved %s to __data section\n", atom.name());
+                                               break;
                                        }
                                }
                        }
-               }
-
-               // add all newly created atoms to fAllAtoms and update symbol table
-               this->addAtoms(newAtoms);
-
-               // add dead atoms to dead list and remove from fAllAtoms
-               for(std::vector<class ObjectFile::Atom*>::iterator itr = newlyDeadAtoms.begin(); itr != newlyDeadAtoms.end(); ++itr) 
-                       markDead(*itr);
-               fAllAtoms.erase(std::remove_if(fAllAtoms.begin(), fAllAtoms.end(), InSet(fDeadAtoms)), fAllAtoms.end());
-
-               // Make sure all atoms have a section.  Atoms that were not originally in a mach-o file could
-               // not have their section set until now.
-               for(std::vector<class ObjectFile::Atom*>::iterator itr = fAllAtoms.begin(); itr != fAllAtoms.end(); ++itr) {
-                       ObjectFile::Atom *atom = *itr;
-                       if ( atom->getSection() == NULL )
-                               atom->setSection(Section::find(atom->getSectionName(), atom->getSegment().getName(), atom->isZeroFill(), true));
-               }
-
-               // resolve new undefines
-               for(std::vector<const char*>::iterator riter = additionalUndefines.begin(); riter != additionalUndefines.end(); ++riter) {
-                       const char *targetName = *riter;
-                       //fprintf(stderr, "LTO additional undefine: %s\n", targetName);
-                       ObjectFile::Atom* target = fGlobalSymbolTable.find(targetName);
-                       if ( target == NULL) {
-                               // mark that this symbol is needed
-                               fGlobalSymbolTable.require(targetName);
-                               // try to find it in some library
-                               this->addJustInTimeAtoms(targetName, true, true, true);
-                       }
-               }
-               
-               if ( fOptions.deadStrip() != Options::kDeadStripOff ) {
-                       // LTO may optimize away some atoms, so dead stripping must be redone
-                       fLiveAtoms.clear();
-                       this->deadStripResolve();
-                       this->checkUndefines();
-               }
-               else {
-                       // LTO may require new library symbols to be loaded, so redo
-                       this->checkUndefines();
-                       this->resolveReferences();
-               }
+                       break;
+               default:
+                       break;
        }
+       
+       //fprintf(stderr, "InternalState::doAtom(%p), name=%s, sect=%s, finalsect=%p\n", &atom, atom.name(), atom.section().sectionName(), fs);
+#ifndef NDEBUG
+       validateFixups(atom);
+#endif
+       fs->atoms.push_back(&atom);
+       return fs;
 }
 
+ld::Internal::FinalSection* InternalState::getFinalSection(const ld::Section& inputSection)
+{      
+       const ld::Section* baseForFinalSection = &inputSection;
+       
+       // see if input section already has a FinalSection
+       SectionInToOut::iterator pos = _sectionInToFinalMap.find(&inputSection);
+       if ( pos != _sectionInToFinalMap.end() ) {
+               return pos->second;
+       }
 
-void Linker::adjustScope()
-{
-       // if -exported_symbols_list is used, demoted to hidden, symbols that are not in it 
-       if ( fOptions.hasExportRestrictList() ) {
-               // The use of an -export file means the previous computation of fHasExternalWeakDefinitions could change
-               fGlobalSymbolTable.setHasExternalWeakDefinitions(false);
-               for(std::vector<class ObjectFile::Atom*>::iterator itr = fAllAtoms.begin(); itr != fAllAtoms.end(); ++itr) {
-                       ObjectFile::Atom *atom = *itr;
-                       ObjectFile::Atom::Scope scope = atom->getScope();
-                       const char* name = atom->getName();
-                       if ( name != NULL ) {
-                               if ( scope == ObjectFile::Atom::scopeGlobal ) {
-                                       // check for globals that are downgraded to hidden
-                                       if ( !fOptions.shouldExport(name) ) {
-                                               atom->setScope(ObjectFile::Atom::scopeLinkageUnit);
-                                               //fprintf(stderr, "demote %s to hidden\n", name);
-                                       }
-                                       else if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition ) {
-                                               if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableIn ) {
-                                                       // we do have an exported weak symbol, turn WEAK_DEFINES back on
-                                                       fGlobalSymbolTable.setHasExternalWeakDefinitions(true);
-                                               }
-                                       }
+       // otherwise, create a new final section
+       bool objFile = false;
+       switch ( _options.outputKind() ) {
+               case Options::kStaticExecutable:
+               case Options::kDynamicExecutable:
+               case Options::kDynamicLibrary:
+               case Options::kDynamicBundle:
+               case Options::kDyld:
+               case Options::kKextBundle:
+               case Options::kPreload:
+                       {
+                               // coalesce some sections
+                               const ld::Section& outSect = FinalSection::outputSection(inputSection);
+                               pos = _sectionInToFinalMap.find(&outSect);
+                               if ( pos != _sectionInToFinalMap.end() ) {
+                                       _sectionInToFinalMap[&inputSection] = pos->second;
+                                       //fprintf(stderr, "_sectionInToFinalMap[%p] = %p\n", &inputSection, pos->second);
+                                       return pos->second;
                                }
-                               else if ( scope == ObjectFile::Atom::scopeLinkageUnit ) {
-                                       // check for hiddens that were requested to be exported
-                                       if ( fOptions.hasExportMaskList() && fOptions.shouldExport(name) ) {
-                                               warning("cannot export hidden symbol %s from %s", name, atom->getFile()->getPath());
-                                       }
+                               else if ( outSect != inputSection ) {
+                                       // new output section created, but not in map
+                                       baseForFinalSection = &outSect;
                                }
                        }
-               }
-       }
-       
-       // linking is done, so demote hidden symbols to static
-       if ( (fOptions.outputKind() == Options::kObjectFile) && fOptions.keepPrivateExterns() ) {
-               // ld -r -keep_private_externs does not move hidden symbols to static
-       }
-       else {
-               for(std::vector<class ObjectFile::Atom*>::iterator itr = fAllAtoms.begin(); itr != fAllAtoms.end(); ++itr) {
-                       ObjectFile::Atom *atom = *itr;
-                       // <rdar://problem/4637139> hidden common symbols cannot be demoted to static
-                       if ( (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit) && (atom->getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition) ) {
-                               atom->setScope(ObjectFile::Atom::scopeTranslationUnit);
-                               //fprintf(stderr, "demote %s to static\n", atom->getDisplayName());
+                       break;
+               case Options::kObjectFile:
+                       baseForFinalSection = &FinalSection::objectOutputSection(inputSection, _options.makeTentativeDefinitionsReal());
+                       pos = _sectionInToFinalMap.find(baseForFinalSection);
+                       if ( pos != _sectionInToFinalMap.end() ) {
+                               _sectionInToFinalMap[&inputSection] = pos->second;
+                               //fprintf(stderr, "_sectionInToFinalMap[%p] = %p\n", &inputSection, pos->second);
+                               return pos->second;
                        }
-               }
+                       objFile = true;
+                       break;
        }
-}
-
-void Linker::link()
-{
-       this->buildAtomList();
-       this->loadAndResolve();
-       this->optimize();
-       this->adjustScope();
-       this->checkObjC();
-       this->processDTrace();
-       this->tweakLayout();
-       this->addSynthesizedAtoms();
-       this->sortSections();
-       this->sortAtoms();
-       this->writeDotOutput();
-       this->collectDebugInfo();
-       this->writeOutput();
-       this->printStatistics();
 
-       if ( fOptions.pauseAtEnd() )
-               sleep(10);
+       InternalState::FinalSection* result = new InternalState::FinalSection(*baseForFinalSection, 
+                                                                                                                                       _sectionInToFinalMap.size(), objFile);
+       _sectionInToFinalMap[baseForFinalSection] = result;
+       //fprintf(stderr, "_sectionInToFinalMap[%p] = %p\n", baseForFinalSection, result);
+       sections.push_back(result);
+       return result;
 }
 
-void Linker::printTime(const char* msg, uint64_t partTime, uint64_t totalTime)
+
+int InternalState::FinalSection::sectionComparer(const void* l, const void* r)
 {
-       static uint64_t sUnitsPerSecond = 0;
-       if ( sUnitsPerSecond == 0 ) {
-               struct mach_timebase_info timeBaseInfo;
-               if ( mach_timebase_info(&timeBaseInfo) == KERN_SUCCESS ) {
-                       sUnitsPerSecond = 1000000000ULL * timeBaseInfo.denom / timeBaseInfo.numer;
-                       //fprintf(stderr, "sUnitsPerSecond=%llu\n", sUnitsPerSecond);
-               }
-       }
-       if ( partTime < sUnitsPerSecond ) {
-               uint32_t milliSecondsTimeTen = (partTime*10000)/sUnitsPerSecond;
-               uint32_t milliSeconds = milliSecondsTimeTen/10;
-               uint32_t percentTimesTen = (partTime*1000)/totalTime;
-               uint32_t percent = percentTimesTen/10;
-               fprintf(stderr, "%s: %u.%u milliseconds (%u.%u%%)\n", msg, milliSeconds, milliSecondsTimeTen-milliSeconds*10, percent, percentTimesTen-percent*10);
-       }
-       else {
-               uint32_t secondsTimeTen = (partTime*10)/sUnitsPerSecond;
-               uint32_t seconds = secondsTimeTen/10;
-               uint32_t percentTimesTen = (partTime*1000)/totalTime;
-               uint32_t percent = percentTimesTen/10;
-               fprintf(stderr, "%s: %u.%u seconds (%u.%u%%)\n", msg, seconds, secondsTimeTen-seconds*10, percent, percentTimesTen-percent*10);
-       }
+       const FinalSection* left  = *(FinalSection**)l;
+       const FinalSection* right = *(FinalSection**)r;
+       if ( left->_segmentOrder != right->_segmentOrder )
+               return (left->_segmentOrder - right->_segmentOrder);
+       return (left->_sectionOrder - right->_sectionOrder);
 }
 
-char* Linker::commatize(uint64_t in, char* out)
+void InternalState::sortSections()
 {
-       char* result = out;
-       char rawNum[30];
-       sprintf(rawNum, "%llu", in);
-       const int rawNumLen = strlen(rawNum);
-       for(int i=0; i < rawNumLen-1; ++i) {
-               *out++ = rawNum[i];
-               if ( ((rawNumLen-i) % 3) == 1 )
-                       *out++ = ',';
-       }
-       *out++ = rawNum[rawNumLen-1];
-       *out = '\0';
-       return result;
+       //fprintf(stderr, "UNSORTED final sections:\n");
+       //for (std::vector<ld::Internal::FinalSection*>::iterator it = sections.begin(); it != sections.end(); ++it) {
+       //      fprintf(stderr, "final section %p %s/%s\n", (*it), (*it)->segmentName(), (*it)->sectionName());
+       //}
+       qsort(&sections[0], sections.size(), sizeof(FinalSection*), &InternalState::FinalSection::sectionComparer);
+       //fprintf(stderr, "SORTED final sections:\n");
+       //for (std::vector<ld::Internal::FinalSection*>::iterator it = sections.begin(); it != sections.end(); ++it) {
+       //      fprintf(stderr, "final section %p %s/%s\n", (*it), (*it)->segmentName(), (*it)->sectionName());
+       //}
+       assert((sections[0]->type() == ld::Section::typeMachHeader) 
+               || ((sections[0]->type() == ld::Section::typeFirstSection) && (sections[1]->type() == ld::Section::typeMachHeader))
+               || ((sections[0]->type() == ld::Section::typePageZero) && (sections[1]->type() == ld::Section::typeMachHeader))
+               || ((sections[0]->type() == ld::Section::typePageZero) && (sections[1]->type() == ld::Section::typeFirstSection) && (sections[2]->type() == ld::Section::typeMachHeader)) );
+       
 }
 
-void Linker::getVMInfo(vm_statistics_data_t& info)
+static void getVMInfo(vm_statistics_data_t& info)
 {
        mach_msg_type_number_t count = sizeof(vm_statistics_data_t) / sizeof(natural_t);
        kern_return_t error = host_statistics(mach_host_self(), HOST_VM_INFO,
@@ -901,3331 +553,113 @@ void Linker::getVMInfo(vm_statistics_data_t& info)
        }
 }
 
-void Linker::printStatistics()
+int main(int argc, const char* argv[])
 {
-       fEndTime = mach_absolute_time();
-       if ( fOptions.printStatistics() ) {
-               vm_statistics_data_t endVMInfo;
-               getVMInfo(endVMInfo);
-
-               uint64_t totalTime = fEndTime - fStartTime;
-               printTime("ld total time", totalTime, totalTime);
-               printTime(" option parsing time",       fStartCreateReadersTime -       fStartTime,                                     totalTime);
-               printTime(" object file processing",fStartCreateWriterTime -    fStartCreateReadersTime,        totalTime);
-               printTime(" output file setup",         fStartBuildAtomsTime -          fStartCreateWriterTime,         totalTime);
-               printTime(" build atom list",           fStartLoadAndResolveTime -      fStartBuildAtomsTime,           totalTime);
-               printTime(" resolve references",        fStartSortTime -                        fStartLoadAndResolveTime,       totalTime);
-               printTime(" sort output",                       fStartDebugTime -                       fStartSortTime,                         totalTime);
-               printTime(" process debug info",        fStartWriteTime -                       fStartDebugTime,                        totalTime);
-               printTime(" write output",                      fEndTime -                                      fStartWriteTime,                        totalTime);
-               fprintf(stderr, "pageins=%u, pageouts=%u, faults=%u\n", endVMInfo.pageins-fStartVMInfo.pageins,
-                                                                               endVMInfo.pageouts-fStartVMInfo.pageouts, endVMInfo.faults-fStartVMInfo.faults);
-               char temp[40];
-               fprintf(stderr, "processed %3u object files,  totaling %15s bytes\n", fTotalObjectLoaded, commatize(fTotalObjectSize, temp));
-               fprintf(stderr, "processed %3u archive files, totaling %15s bytes\n", fTotalArchivesLoaded, commatize(fTotalArchiveSize, temp));
-               fprintf(stderr, "processed %3u dylib files\n", fTotalDylibsLoaded);
-               fprintf(stderr, "wrote output file            totaling %15s bytes\n", commatize(fOutputFileSize, temp));
+#if DEBUG
+       usleep(1000000);
+#endif
+       const char* archName = NULL;
+       bool showArch = false;
+       bool archInferred = false;
+       try {
+               vm_statistics_data_t vmStart;
+               vm_statistics_data_t vmEnd;
+               getVMInfo(vmStart);
+       
+               // create object to track command line arguments
+               Options options(argc, argv);
+               
+               // gather stats
+               if ( options.printStatistics() )
+                       getVMInfo(vmStart);
+
+               // update strings for error messages
+               showArch = options.printArchPrefix();
+               archName = options.architectureName();
+               archInferred = (options.architecture() == 0);
+               
+               // open and parse input files
+               ld::tool::InputFiles inputFiles(options, &archName);
+               
+               // load and resolve all references
+               InternalState state(options);
+               ld::tool::Resolver resolver(options, inputFiles, state);
+               resolver.resolve();
+                               
+               // add dylibs used
+               inputFiles.dylibs(state);
+       
+               // do initial section sorting so passes have rough idea of the layout
+               state.sortSections();
+
+               // run passes
+               ld::passes::objc::doPass(options, state);
+               ld::passes::stubs::doPass(options, state);
+               ld::passes::huge::doPass(options, state);
+               ld::passes::got::doPass(options, state);
+               ld::passes::tlvp::doPass(options, state);
+               ld::passes::dylibs::doPass(options, state);     // must be after stubs and GOT passes
+               ld::passes::order_file::doPass(options, state);
+               ld::passes::branch_shim::doPass(options, state);        // must be after stubs 
+               ld::passes::branch_island::doPass(options, state);      // must be after stubs and order_file pass
+               ld::passes::dtrace::doPass(options, state);
+               ld::passes::compact_unwind::doPass(options, state);  // must be after order-file pass
+               
+               // sort final sections
+               state.sortSections();
+
+               // write output file
+               ld::tool::OutputFile out(options);
+               out.write(state);
+               
+               // print statistics
+               //mach_o::relocatable::printCounts();
+               if ( options.printStatistics() ) {
+                       getVMInfo(vmEnd);
+                       fprintf(stderr, "pageins=%u, pageouts=%u, faults=%u\n", vmEnd.pageins-vmStart.pageins,
+                                                                               vmEnd.pageouts-vmStart.pageouts, vmEnd.faults-vmStart.faults);
+                       
+               }
+       }
+       catch (const char* msg) {
+               if ( archInferred )
+                       fprintf(stderr, "ld: %s for inferred architecture %s\n", msg, archName);
+               else if ( showArch )
+                       fprintf(stderr, "ld: %s for architecture %s\n", msg, archName);
+               else
+                       fprintf(stderr, "ld: %s\n", msg);
+               return 1;
        }
+
+       return 0;
 }
 
-inline void Linker::addAtom(ObjectFile::Atom& atom)
+
+#ifndef NDEBUG
+// implement assert() function to print out a backtrace before aborting
+void __assert_rtn(const char* func, const char* file, int line, const char* failedexpr)
 {
-       // add to list of all atoms
-       fAllAtoms.push_back(&atom);
+       fprintf(stderr, "Assertion failed: (%s), function %s, file %s, line %d.\n", failedexpr, func, file, line);
 
-       if ( fOptions.deadStrip() == Options::kDeadStripOff ) {
-               // not dead-stripping code, so add atom's references's names to symbol table as to-be-resolved-later
-               std::vector<class ObjectFile::Reference*>& references = atom.getReferences();
-               for (std::vector<ObjectFile::Reference*>::iterator it=references.begin(); it != references.end(); it++) {
-                       ObjectFile::Reference* reference = *it;
-                       if ( reference->getTargetBinding() == ObjectFile::Reference::kUnboundByName )
-                               fGlobalSymbolTable.require(reference->getTargetName());
-                       if ( reference->getFromTargetBinding() == ObjectFile::Reference::kUnboundByName )
-                               fGlobalSymbolTable.require(reference->getFromTargetName());
-               }
-               // update total size info (except for __ZEROPAGE atom)
-               if ( atom.getSegment().isContentReadable() ) {
-                       fTotalSize += atom.getSize();
-                       if ( atom.isZeroFill() )
-                               fTotalZeroFillSize += atom.getSize();
+       void* callStack[128];
+       int depth = ::backtrace(callStack, 128);
+       char* buffer = (char*)malloc(1024);
+       for(int i=0; i < depth-1; ++i) {
+               Dl_info info;
+               dladdr(callStack[i], &info);
+               const char* symboName = info.dli_sname;
+               if ( (symboName != NULL) && (strncmp(symboName, "_Z", 2) == 0) ) {
+                       size_t bufLen = 1024;
+                       int result;
+                       char* unmangled = abi::__cxa_demangle(symboName, buffer, &bufLen, &result);
+                       if ( unmangled != NULL )
+                               symboName = unmangled;
                }
+               long offset = (uintptr_t)callStack[i] - (uintptr_t)info.dli_saddr;
+               fprintf(stderr, "%d  %p  %s + %ld\n", i, callStack[i], symboName, offset);
        }
-       else {
-               if ( atom.dontDeadStrip() )
-                       fLiveRootAtoms.insert(&atom);
-       }
+       exit(1);
+}
+#endif
 
-       // if in global namespace, add atom itself to symbol table
-       ObjectFile::Atom::Scope scope = atom.getScope();
-       const char* name = atom.getName();
-       if ( (scope != ObjectFile::Atom::scopeTranslationUnit) && (name != NULL) ) {
-               // add to symbol table
-               fGlobalSymbolTable.add(atom);
-       }
 
-       // record section orders so output file can have same order
-       if (atom.getSectionName()) {
-               bool untrusted = false;
-               switch ( atom.getContentType() ) {
-                       case ObjectFile::Atom::kSectionStart:
-                       case ObjectFile::Atom::kSectionEnd:
-                               untrusted = true;
-                       default:
-                               break;
-               }
-               atom.setSection(Section::find(atom.getSectionName(), atom.getSegment().getName(), atom.isZeroFill(), untrusted));
-       }
-}
-
-
-void Linker::markDead(ObjectFile::Atom* atom)
-{
-       //fprintf(stderr, "markDead(%p) %s from %s\n", atom, atom->getDisplayName(), atom->getFile()->getPath());
-       fDeadAtoms.insert(atom);
-       
-       // <rdar://problem/6578360> -dead_strip inhibits weak coalescing in no_dead_strip section
-       if ( fLiveRootAtoms.count(atom) != 0 ) {
-               fLiveRootAtoms.erase(atom);
-       }
-       
-       //
-       // The kGroupSubordinate reference kind is used to model group comdat.  
-       // The "signature" atom in the group has a kGroupSubordinate reference to
-       // all other members of the group.  So, if the signature atom is 
-       // coalesced away, all other atoms in the group should also be removed.  
-       //
-       std::vector<class ObjectFile::Reference*>& references = atom->getReferences();
-       for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
-               ObjectFile::Reference* ref = *rit;
-               if ( ref->getKind() == 2 /*kGroupSubordinate*/ ) {      // FIX FIX
-                       ObjectFile::Atom* targetAtom = &(ref->getTarget());
-                       //fprintf(stderr, "  markDead(%p) subordinate %s\n", targetAtom, targetAtom->getDisplayName());
-                       if ( targetAtom == NULL ) {
-                               warning("%s has a group reference to %s but is not bound", atom->getDisplayName(), ref->getTargetName());
-                       }
-                       else {
-                               if ( targetAtom->getScope() != ObjectFile::Atom::scopeTranslationUnit ) {
-                                       // ok for .eh symbols to be not static in -r mode
-                                       if ( (fOptions.outputKind() != Options::kObjectFile) || (strcmp(targetAtom->getSectionName(), "__eh_frame") != 0) )
-                                               warning("%s is in a comdat group but its scope is not static", targetAtom->getDisplayName());
-                               }
-                               this->markDead(targetAtom);
-                       }
-               }
-       }
-}
-
-void Linker::updateConstraints(ObjectFile::Reader* reader)
-{
-       // check objc objects were compiled compatibly
-       ObjectFile::Reader::ObjcConstraint objcAddition = reader->getObjCConstraint();
-       if ( reader->getInstallPath() == NULL ) {
-               // adding a .o file
-               switch ( objcAddition ) {
-                       case ObjectFile::Reader::kObjcNone:
-                               break;
-                       case ObjectFile::Reader::kObjcRetainRelease:
-                               if ( fCurrentObjCConstraint == ObjectFile::Reader::kObjcGC )
-                                       throwf("%s built with incompatible Garbage Collection settings to link with previous .o files", reader->getPath());
-                               fCurrentObjCConstraint = ObjectFile::Reader::kObjcRetainRelease;
-                               break;
-                       case ObjectFile::Reader::kObjcRetainReleaseOrGC:
-                               if ( fCurrentObjCConstraint == ObjectFile::Reader::kObjcNone )
-                                       fCurrentObjCConstraint = ObjectFile::Reader::kObjcRetainReleaseOrGC;
-                               break;
-                       case ObjectFile::Reader::kObjcGC:
-                               if ( fCurrentObjCConstraint == ObjectFile::Reader::kObjcRetainRelease )
-                                       throwf("%s built with incompatible Garbage Collection settings to link with previous .o files", reader->getPath());
-                               fCurrentObjCConstraint = ObjectFile::Reader::kObjcGC;
-                               break;
-               }
-       }
-       if ( reader->objcReplacementClasses() )
-               fObjcReplacmentClasses = true;
-
-       // check cpu sub-types for stricter sub-type
-       fCurrentCpuConstraint = (ObjectFile::Reader::CpuConstraint)reader->updateCpuConstraint(fCurrentCpuConstraint);
-}
-
-inline void Linker::addAtoms(std::vector<class ObjectFile::Atom*>& atoms)
-{
-       bool scanAll = fOptions.readerOptions().fFullyLoadArchives || fOptions.readerOptions().fLoadAllObjcObjectsFromArchives;
-       bool first = true; 
-       for (std::vector<ObjectFile::Atom*>::iterator it=atoms.begin(); it != atoms.end(); it++) {
-               // usually we only need to get the first atom's reader, but
-               // with -all_load all atoms from all .o files come come back together
-               // so we need to scan all atoms
-               if ( first || scanAll ) {
-                       // update fReadersThatHaveSuppliedAtoms
-                       ObjectFile::Reader* reader = (*it)->getFile();
-                       if ( std::find(fReadersThatHaveSuppliedAtoms.begin(), fReadersThatHaveSuppliedAtoms.end(), reader)
-                                       == fReadersThatHaveSuppliedAtoms.end() ) {
-                               fReadersThatHaveSuppliedAtoms.push_back(reader);
-                               updateConstraints(reader);                              
-                       }       
-               }
-               this->addAtom(**it);
-               first = false;
-       }
-}
-
-void Linker::logArchive(ObjectFile::Reader* reader)
-{
-       if ( (fArchiveReaders.count(reader) != 0) && (fArchiveReadersLogged.count(reader) == 0) ) {
-               fArchiveReadersLogged.insert(reader);
-               const char* fullPath = reader->getPath();
-               char realName[MAXPATHLEN];
-               if ( realpath(fullPath, realName) != NULL )
-                       fullPath = realName;
-               logTraceInfo("[Logging for XBS] Used static archive: %s\n", fullPath);
-       }
-}
-
-
-void Linker::buildAtomList()
-{
-       fStartBuildAtomsTime = mach_absolute_time();
-       // add initial undefines from -u option
-       std::vector<const char*>& initialUndefines = fOptions.initialUndefines();
-       for (std::vector<const char*>::iterator it=initialUndefines.begin(); it != initialUndefines.end(); it++) {
-               fGlobalSymbolTable.require(*it);
-       }
-
-       // writer can contribute atoms
-       this->addAtoms(fOutputFile->getAtoms());
-
-       // each reader contributes atoms
-       for (std::vector<class ObjectFile::Reader*>::iterator it=fInputFiles.begin(); it != fInputFiles.end(); it++) {
-               ObjectFile::Reader* reader = *it;
-               std::vector<class ObjectFile::Atom*>& atoms = reader->getAtoms();
-               this->addAtoms(atoms);
-               if ( fOptions.readerOptions().fTraceArchives && (atoms.size() != 0) ) 
-                       logArchive(reader);
-       }
-
-       // extra command line section always at end
-       std::vector<Options::ExtraSection>& extraSections = fOptions.extraSections();
-       for( std::vector<Options::ExtraSection>::iterator it=extraSections.begin(); it != extraSections.end(); ++it) {
-               this->addAtoms((new opaque_section::Reader(it->segmentName, it->sectionName, it->path, it->data, it->dataLen, fNextInputOrdinal))->getAtoms());
-               fNextInputOrdinal += it->dataLen;
-       }
-       
-       // done with all .o files on command line
-       // everything loaded from now on is a just-in-time atom
-       fInitialLoadsDone = true;
-}
-
-static const char* pathLeafName(const char* path)
-{
-       const char* shortPath = strrchr(path, '/');
-       if ( shortPath == NULL )
-               return path;
-       else
-               return &shortPath[1];
-}
-
-
-void Linker::loadUndefines()
-{
-       // keep looping until no more undefines were added in last loop
-       unsigned int undefineCount = 0xFFFFFFFF;
-       while ( undefineCount != fGlobalSymbolTable.getRequireCount() ) {
-               undefineCount = fGlobalSymbolTable.getRequireCount();
-               std::vector<const char*> undefineNames;
-               fGlobalSymbolTable.getUndefinesNames(undefineNames);
-               for(std::vector<const char*>::iterator it = undefineNames.begin(); it != undefineNames.end(); ++it) {
-                       // load for previous undefine may also have loaded this undefine, so check again
-                       if ( fGlobalSymbolTable.find(*it) == NULL ) {
-                               std::vector<class ObjectFile::Atom*>* atoms = this->addJustInTimeAtoms(*it, true, true, true);
-                               if ( atoms != NULL ) 
-                                       delete atoms;
-                       }
-               }
-               // <rdar://problem/5894163> need to search archives for overrides of common symbols 
-               if ( fGlobalSymbolTable.hasExternalTentativeDefinitions() ) {
-                       bool searchDylibs = (fOptions.commonsMode() == Options::kCommonsOverriddenByDylibs);
-                       std::vector<const char*> tentativeDefinitionNames;
-                       fGlobalSymbolTable.getTentativesNames(tentativeDefinitionNames);
-                       for(std::vector<const char*>::iterator it = tentativeDefinitionNames.begin(); it != tentativeDefinitionNames.end(); ++it) {
-                               // load for previous tentative  may also have overridden this tentative, so check again                                                
-                               ObjectFile::Atom* tent = fGlobalSymbolTable.find(*it);
-                               if ( (tent != NULL) && (tent->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition) ) {
-                                       std::vector<class ObjectFile::Atom*>* atoms = this->addJustInTimeAtoms(*it, searchDylibs, true, false);
-                                       if ( atoms != NULL ) 
-                                               delete atoms;
-                               }
-                       }
-               }
-       }
-}
-
-// temp hack for rdar://problem/4718189 map ObjC class names to new runtime names
-class ExportedObjcClass
-{
-public:
-       ExportedObjcClass(Options& opt) : fOptions(opt)  {}
-
-       bool operator()(const char* name) const {
-               if ( fOptions.shouldExport(name) ) {
-                       if ( strncmp(name, ".objc_class_name_", 17) == 0 )
-                               return true;
-                       if ( strncmp(name, "_OBJC_CLASS_$_", 14) == 0 )
-                               return true;
-                       if ( strncmp(name, "_OBJC_METACLASS_$_", 18) == 0 )
-                               return true;
-               }
-               //fprintf(stderr, "%s is not exported\n", name);
-               return false;
-       }
-private:
-       Options& fOptions;
-};
-
-
-void Linker::checkUndefines()
-{
-       // error out on any remaining undefines
-       bool doPrint = true;
-       bool doError = true;
-       switch ( fOptions.undefinedTreatment() ) {
-               case Options::kUndefinedError:
-                       break;
-               case Options::kUndefinedDynamicLookup:
-                       doError = false;
-                       break;
-               case Options::kUndefinedWarning:
-                       doError = false;
-                       break;
-               case Options::kUndefinedSuppress:
-                       doError = false;
-                       doPrint = false;
-                       break;
-       }
-       std::vector<const char*> unresolvableUndefines;
-       fGlobalSymbolTable.getUndefinesNames(unresolvableUndefines);
-
-       // temp hack for rdar://problem/4718189 map ObjC class names to new runtime names
-       // ignore unresolved references to Objc class names that are listed in -exported_symbols_list
-       if ( fOptions.hasExportRestrictList() )
-               unresolvableUndefines.erase(std::remove_if(unresolvableUndefines.begin(), unresolvableUndefines.end(), ExportedObjcClass(fOptions)), unresolvableUndefines.end());
-
-       const int unresolvableCount = unresolvableUndefines.size();
-       int unresolvableExportsCount  = 0;
-       if ( unresolvableCount != 0 ) {
-               if ( doPrint ) {
-                       if ( fOptions.printArchPrefix() )
-                               fprintf(stderr, "Undefined symbols for architecture %s:\n", fArchitectureName);
-                       else
-                               fprintf(stderr, "Undefined symbols:\n");
-                       for (int i=0; i < unresolvableCount; ++i) {
-                               const char* name = unresolvableUndefines[i];
-                               fprintf(stderr, "  \"%s\", referenced from:\n", name);
-                               // scan all atoms for references
-                               bool foundAtomReference = false;
-                               for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
-                                       ObjectFile::Atom* atom = *it;
-                                       std::vector<class ObjectFile::Reference*>& references = atom->getReferences();
-                                       for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
-                                               ObjectFile::Reference* reference = *rit;
-                                               if ( reference->getTargetBinding() == ObjectFile::Reference::kUnboundByName ) {
-                                                       if ( strcmp(reference->getTargetName(), name) == 0 ) {
-                                                               fprintf(stderr, "      %s in %s\n", atom->getDisplayName(), pathLeafName(atom->getFile()->getPath()));
-                                                               foundAtomReference = true;
-                                                       }
-                                               }
-                                               if ( reference->getFromTargetBinding() == ObjectFile::Reference::kUnboundByName ) {
-                                                       if ( strcmp(reference->getFromTargetName(), name) == 0 ) {
-                                                               fprintf(stderr, "      %s in %s\n", atom->getDisplayName(), pathLeafName(atom->getFile()->getPath()));
-                                                               foundAtomReference = true;
-                                                       }
-                                               }
-                                       }
-                               }
-                               // scan command line options
-                               if  ( !foundAtomReference ) {
-                                       // might be from -init command line option
-                                       if ( (fOptions.initFunctionName() != NULL) && (strcmp(name, fOptions.initFunctionName()) == 0) ) {
-                                               fprintf(stderr, "     -init command line option\n");
-                                       }
-                                       // or might be from exported symbol option
-                                       else if ( fOptions.hasExportMaskList() && fOptions.shouldExport(name) ) {
-                                               fprintf(stderr, "     -exported_symbol[s_list] command line option\n");
-                                       }
-                                       else {
-                                               bool isInitialUndefine = false;
-                                               std::vector<const char*>& clundefs = fOptions.initialUndefines();
-                                               for (std::vector<const char*>::iterator uit = clundefs.begin(); uit != clundefs.end(); ++uit) {
-                                                       if ( strcmp(*uit, name) == 0 ) {
-                                                               isInitialUndefine = true;
-                                                               break;
-                                                       }
-                                               }
-                                               if ( isInitialUndefine )
-                                                       fprintf(stderr, "     -u command line option\n");
-                                       }
-                                       ++unresolvableExportsCount;
-                               }
-                               // be helpful and check for typos
-                               bool printedStart = false;
-                               for (SymbolTable::Mapper::iterator sit=fGlobalSymbolTable.begin(); sit != fGlobalSymbolTable.end(); ++sit) {
-                                       if ( (sit->second != NULL) && (strstr(sit->first, name) != NULL) ) {
-                                               if ( ! printedStart ) {
-                                                       fprintf(stderr, "     (maybe you meant: %s", sit->first);
-                                                       printedStart = true;
-                                               }
-                                               else {
-                                                       fprintf(stderr, ", %s ", sit->first);
-                                               }
-                                       }
-                               }
-                               if ( printedStart )
-                                       fprintf(stderr, ")\n");
-                       }
-               }
-               if ( doError ) 
-                       throw "symbol(s) not found";
-       }
-       
-       // for each tentative definition in symbol table look for dylib that exports same symbol name
-       if ( fGlobalSymbolTable.hasExternalTentativeDefinitions() ) {
-               for (SymbolTable::Mapper::iterator it=fGlobalSymbolTable.begin(); it != fGlobalSymbolTable.end(); ++it) {
-                       ObjectFile::Atom* atom = it->second;
-                       if ( (atom != NULL) && (atom->getDefinitionKind()==ObjectFile::Atom::kTentativeDefinition) 
-                               && (atom->getScope() == ObjectFile::Atom::scopeGlobal) ) {
-                               // look for dylibs that export same name as used by global tentative definition
-                               addJustInTimeAtoms(atom->getName(), true, false, false);
-                       }
-               }
-       }
-       
-       
-       // record any overrides of weak symbols any linked dylib 
-       for (SymbolTable::Mapper::iterator it=fGlobalSymbolTable.begin(); it != fGlobalSymbolTable.end(); ++it) {
-               ObjectFile::Atom* atom = it->second;
-               if ( (atom != NULL) && (atom->getDefinitionKind()==ObjectFile::Atom::kRegularDefinition) 
-                       && (atom->getScope() == ObjectFile::Atom::scopeGlobal) ) {
-                       const char* name = atom->getName();
-                       //fprintf(stderr, "looking for dylibs with a weak %s\n", name);
-                       // look for dylibs with weak exports of the same name 
-                       for (InstallNameToReader::iterator it=fDylibMap.begin(); it != fDylibMap.end(); it++) {
-                               ObjectFile::Reader* reader = it->second;
-                               if ( reader->hasWeakExternals() ) {
-                                       std::vector<class ObjectFile::Atom*>* dylibAtoms = reader->getJustInTimeAtomsFor(name);
-                                       if ( dylibAtoms != NULL ) {
-                                               //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, reader->getPath() );
-                                               // if this is a weak definition in a dylib
-                                               if ( (dylibAtoms->at(0)->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
-                                                       fRegularDefAtomsThatOverrideADylibsWeakDef.insert(atom);
-                                               }
-                                       }
-                               }
-                       }
-               }
-       }
-       
-}
-
-
-
-std::vector<class ObjectFile::Atom*>* Linker::addJustInTimeAtoms(const char* name, bool searchDylibs, bool searchArchives, bool okToMakeProxy)
-{
-       //fprintf(stderr, "addJustInTimeAtoms(%s, searchDylibs=%d, searchArchives=%d)\n", name, searchDylibs, searchArchives );
-       // when creating final linked image, writer gets first chance
-       if ( fOptions.outputKind() != Options::kObjectFile ) {
-               std::vector<class ObjectFile::Atom*>* atoms = fOutputFile->getJustInTimeAtomsFor(name);
-               if ( atoms != NULL ) {
-                       this->addAtoms(*atoms);
-                       //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, fOutputFile->getPath() );
-                       return atoms;  // found a definition, no need to search anymore
-               }
-       }
-
-       // give readers a chance
-       for (std::vector<class ObjectFile::Reader*>::iterator it=fInputFiles.begin(); it != fInputFiles.end(); it++) {
-               ObjectFile::Reader* reader = *it;
-               if ( reader != NULL ) {
-                       // 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.
-                       //fprintf(stderr, "addJustInTimeAtoms(%s), looking in reader %s\n", name, reader->getPath() );
-                       bool isDylibReader = (reader->getInstallPath() != NULL);
-                       if ( isDylibReader ? searchDylibs : searchArchives ) {
-                               std::vector<class ObjectFile::Atom*>* atoms = reader->getJustInTimeAtomsFor(name);
-                               if ( atoms != NULL ) {
-                                       this->addAtoms(*atoms);
-                                       //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, reader->getPath() );
-                                       if ( !isDylibReader && fOptions.readerOptions().fTraceArchives ) {
-                                               logArchive(reader);
-                                       }
-                                       // if this is a weak definition in a dylib
-                                       if ( isDylibReader && (atoms->size() == 1) && (atoms->at(0)->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
-                                               // keep looking for a non-weak definition
-                                       }
-                                       else {
-                                               // found a definition, no need to search anymore
-                                               return atoms;  
-                                       }
-                               }
-                       }
-               }
-       }
-
-       // for two level namesapce, give all implicitly link dylibs a chance
-       if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace ) {
-               for (InstallNameToReader::iterator it=fDylibMap.begin(); it != fDylibMap.end(); it++) {
-                       if ( it->second->implicitlyLinked() ) {
-                               //fprintf(stderr, "addJustInTimeAtoms(%s), looking in implicitly linked %s\n", name, it->second->getPath() );
-                               std::vector<class ObjectFile::Atom*>* atoms = it->second->getJustInTimeAtomsFor(name);
-                               if ( atoms != NULL ) {
-                                       this->addAtoms(*atoms);
-                                       //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, reader->getPath() );
-                                       // if this is a weak definition in a dylib
-                                       if ( (atoms->size() == 1) && (atoms->at(0)->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
-                                               // keep looking for a non-weak definition
-                                       }
-                                       else {
-                                               // found a definition, no need to search anymore
-                                               return atoms;  
-                                       }
-                               }
-                       }
-               }
-       }
-
-       // for flat namespace, give indirect dylibs
-       if ( fOptions.nameSpace() != Options::kTwoLevelNameSpace ) {
-               for (InstallNameToReader::iterator it=fDylibMap.begin(); it != fDylibMap.end(); it++) {
-                       if ( ! it->second->explicitlyLinked() ) {
-                               std::vector<class ObjectFile::Atom*>* atoms = it->second->getJustInTimeAtomsFor(name);
-                               if ( atoms != NULL ) {
-                                       this->addAtoms(*atoms);
-                                       //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, reader->getPath() );
-                                       return atoms;  // found a definition, no need to search anymore
-                               }
-                       }
-               }
-       }
-
-       // writer creates a proxy in two cases:
-       // 1) ld -r is being used to create a .o file 
-       // 2) -undefined dynamic_lookup is being used
-       // 3) -U _foo is being used
-       // 4) x86_64 kext bundle is being created
-       if (    (fOptions.outputKind() == Options::kObjectFile) 
-               ||  ((fOptions.undefinedTreatment() != Options::kUndefinedError) && okToMakeProxy)
-               ||      (fOptions.someAllowedUndefines() && okToMakeProxy) 
-               ||  (fOptions.outputKind() == Options::kKextBundle) ) {
-               ObjectFile::Atom* atom = fOutputFile->getUndefinedProxyAtom(name);
-               if ( atom != NULL ) {
-                       this->addAtom(*atom);
-                       return NULL;
-               }
-       }
-       //fprintf(stderr, "addJustInTimeAtoms(%s) => not found\n", name);
-       return NULL;
-}
-
-void Linker::resolve(ObjectFile::Reference* reference)
-{
-       // look in global symbol table
-       const char* targetName = reference->getTargetName();
-       ObjectFile::Atom* target = fGlobalSymbolTable.find(targetName);
-       if ( target == NULL ) {
-               throwf("unexpected undefined symbol: %s", targetName);
-       }
-       reference->setTarget(*target, reference->getTargetOffset());
-}
-
-void Linker::resolveFrom(ObjectFile::Reference* reference)
-{
-       // handle references that have two (from and to) targets
-       const char* fromTargetName = reference->getFromTargetName();
-       ObjectFile::Atom* fromTarget = fGlobalSymbolTable.find(fromTargetName);
-       if ( fromTarget == NULL ) {
-               throwf("unexpected undefined symbol: %s", fromTargetName);
-       }
-       reference->setFromTarget(*fromTarget);
-}
-
-
-void Linker::resolveReferences()
-{
-       // note: the atom list may grow during this loop as libraries supply needed atoms
-       for (unsigned int j=0; j < fAllAtoms.size(); ++j) {
-               ObjectFile::Atom* atom = fAllAtoms[j];
-               std::vector<class ObjectFile::Reference*>& references = atom->getReferences();
-               for (std::vector<ObjectFile::Reference*>::iterator it=references.begin(); it != references.end(); it++) {
-                       ObjectFile::Reference* reference = *it;
-                       if ( reference->getTargetBinding() == ObjectFile::Reference::kUnboundByName )
-                               this->resolve(reference);
-                       if ( reference->getFromTargetBinding() == ObjectFile::Reference::kUnboundByName )
-                               this->resolveFrom(reference);
-               }
-       }
-}
-
-
-// used to remove stabs associated with atoms that won't be in output file
-class NotInSet
-{
-public:
-       NotInSet(std::set<ObjectFile::Atom*>& theSet) : fSet(theSet) {}
-
-       bool operator()(const ObjectFile::Reader::Stab& stab) const {
-               if ( stab.atom == NULL )
-                       return false;   // leave stabs that are not associated with any atome
-               else
-                       return ( fSet.count(stab.atom) == 0 );
-       }
-
-private:
-       std::set<ObjectFile::Atom*>& fSet;
-};
-
-
-class NotLive
-{
-public:
-       NotLive(std::set<ObjectFile::Atom*>& set) : fLiveAtoms(set)  {}
-
-       bool operator()(ObjectFile::Atom*& atom) const {
-               //if ( fLiveAtoms.count(atom) == 0 )
-               //      fprintf(stderr, "dead strip %s\n", atom->getDisplayName());
-               return ( fLiveAtoms.count(atom) == 0 );
-       }
-private:
-       std::set<ObjectFile::Atom*>& fLiveAtoms;
-};
-
-
-void Linker::addJustInTimeAtomsAndMarkLive(const char* name)
-{
-       //fprintf(stderr, "addJustInTimeAtomsAndMarkLive(%s)\n", name);
-       std::vector<class ObjectFile::Atom*>* atoms = this->addJustInTimeAtoms(name, true, true, true);
-       if ( atoms != NULL ) {
-               if ( fOptions.allGlobalsAreDeadStripRoots() ) {
-                       for (std::vector<ObjectFile::Atom*>::iterator it=atoms->begin(); it != atoms->end(); it++) {
-                               ObjectFile::Atom* atom = *it;
-                               if ( atom->getScope() ==  ObjectFile::Atom::scopeGlobal ) {
-                                       WhyLiveBackChain rootChain;
-                                       rootChain.previous = NULL;
-                                       rootChain.referer = atom;
-                                       this->markLive(*atom, &rootChain);
-                               }
-                       }
-               }
-               delete atoms;
-       }
-}
-
-void Linker::markLive(ObjectFile::Atom& atom, struct Linker::WhyLiveBackChain* previous)
-{
-       //fprintf(stderr, "markLive(%p)\n", &atom);
-       if ( fLiveAtoms.count(&atom) == 0 ) {
-               // if -why_live cares about this symbol, then dump chain
-               if ( (previous->referer != NULL) && fOptions.printWhyLive(previous->referer->getDisplayName()) ) {
-                       int depth = 0;
-                       for(WhyLiveBackChain* p = previous; p != NULL; p = p->previous, ++depth) {
-                               for(int i=depth; i > 0; --i)
-                                       fprintf(stderr, "  ");
-                               fprintf(stderr, "%p %s from %s\n", p->referer, p->referer->getDisplayName(), p->referer->getFile()->getPath());
-                       }
-               }
-               // set up next chain
-               WhyLiveBackChain thisChain;
-               thisChain.previous = previous;
-               // this atom is live
-               fLiveAtoms.insert(&atom);
-               // update total size info (except for __ZEROPAGE atom)
-               if ( atom.getSegment().isContentReadable() ) {
-                       fTotalSize += atom.getSize();
-                       if ( atom.isZeroFill() )
-                               fTotalZeroFillSize += atom.getSize();
-               }
-               // and all atoms it references
-               std::vector<class ObjectFile::Reference*>& references = atom.getReferences();
-               for (std::vector<ObjectFile::Reference*>::iterator it=references.begin(); it != references.end(); it++) {
-                       ObjectFile::Reference* reference = *it;
-                       if ( reference->getTargetBinding() == ObjectFile::Reference::kUnboundByName ) {
-                               // look in global symbol table
-                               const char* targetName = reference->getTargetName();
-                               ObjectFile::Atom* target = fGlobalSymbolTable.find(targetName);
-                               if ( (target == NULL) || (target->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition) ) {
-                                       // load archives or dylibs
-                                       this->addJustInTimeAtomsAndMarkLive(targetName);
-                               }
-                               // look again
-                               target = fGlobalSymbolTable.find(targetName);
-                               if ( target != NULL ) {
-                                       reference->setTarget(*target, reference->getTargetOffset());
-                               }
-                               else {
-                                       // mark as undefined, for later error processing
-                                       fAtomsWithUnresolvedReferences.push_back(&atom);
-                                       fGlobalSymbolTable.require(targetName);
-                               }
-                       }
-                       switch ( reference->getTargetBinding() ) {
-                               case ObjectFile::Reference::kBoundDirectly:
-                               case ObjectFile::Reference::kBoundByName:
-                                       thisChain.referer = &reference->getTarget();
-                                       markLive(reference->getTarget(), &thisChain);
-                                       break;
-                               case ObjectFile::Reference::kDontBind:
-                               case ObjectFile::Reference::kUnboundByName:
-                                       // do nothing
-                                       break;
-                       }
-                       // do the same as above, for "from target"
-                       if ( reference->getFromTargetBinding() == ObjectFile::Reference::kUnboundByName ) {
-                               // look in global symbol table
-                               const char* targetName = reference->getFromTargetName();
-                               ObjectFile::Atom* target = fGlobalSymbolTable.find(targetName);
-                               if ( (target == NULL) || (target->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition) ) {
-                                       // load archives or dylibs
-                                       this->addJustInTimeAtomsAndMarkLive(targetName);
-                               }
-                               // look again
-                               target = fGlobalSymbolTable.find(targetName);
-                               if ( target != NULL ) {
-                                       reference->setFromTarget(*target);
-                               }
-                               else {
-                                       // mark as undefined, for later error processing
-                                       fGlobalSymbolTable.require(targetName);
-                               }
-                       }
-                       switch ( reference->getFromTargetBinding() ) {
-                               case ObjectFile::Reference::kBoundDirectly:
-                               case ObjectFile::Reference::kBoundByName:
-                                       thisChain.referer = &reference->getFromTarget();
-                                       markLive(reference->getFromTarget(), &thisChain);
-                                       break;
-                               case ObjectFile::Reference::kUnboundByName:
-                               case ObjectFile::Reference::kDontBind:
-                                       // do nothing
-                                       break;
-                       }
-               }
-       }
-}
-
-
-void Linker::addLiveRoot(const char* name)
-{
-       ObjectFile::Atom* target = fGlobalSymbolTable.find(name);
-       if ( target == NULL ) {
-               this->addJustInTimeAtomsAndMarkLive(name);
-               target = fGlobalSymbolTable.find(name);
-       }
-       if ( target != NULL )
-               fLiveRootAtoms.insert(target);
-}
-
-void Linker::moveToFrontOfSection(ObjectFile::Atom* atom)
-{
-       // check if already moved to front
-       if ( fInitializerAtoms.find(atom) == fInitializerAtoms.end() ) {
-               // don't re-order initializers from .o files without MH_SUBSECTIONS_VIA_SYMBOLS
-               // since that could make all atoms in the file look like initializers 
-               if ( atom->getFile()->canScatterAtoms() ) {
-                       //fprintf(stdout, "marking as initializer: %s\n", atom->getDisplayName());
-                       fInitializerAtoms.insert(atom);
-                       // mark all functions that this function references
-                       std::vector<class ObjectFile::Reference*>& references = atom->getReferences();
-                       for (std::vector<ObjectFile::Reference*>::const_iterator rit=references.begin(); rit != references.end(); rit++) {
-                               ObjectFile::Atom* childAtom = &((*rit)->getTarget());
-                               if ( childAtom != NULL ) {
-                                       if ( (*rit)->isBranch() ) {
-                                               this->moveToFrontOfSection(childAtom);
-                                       }
-                                       else if ( (childAtom->getName() != NULL) && (strncmp(childAtom->getName(), "___tcf_", 7) == 0) ) {
-                                               //fprintf(stdout, "marking as terminator: %s\n", childAtom->getDisplayName());
-                                               fTerminatorAtoms.insert(childAtom);
-                                       }
-                               }
-                       }
-               }
-       }
-}
-
-void Linker::deadStripResolve()
-{
-       // add main() to live roots
-       ObjectFile::Atom* entryPoint = this->entryPoint(false, true);
-       if ( entryPoint != NULL )
-               fLiveRootAtoms.insert(entryPoint);
-
-       // add dyld_stub_binding_helper/dyld_stub_binder to live roots
-       ObjectFile::Atom* dyldHelper = this->dyldClassicHelper();
-       if ( dyldHelper != NULL )
-               fLiveRootAtoms.insert(dyldHelper);
-       dyldHelper = this->dyldCompressedHelper();
-       if ( dyldHelper != NULL )
-               fLiveRootAtoms.insert(dyldHelper);
-
-       // if using lazy dylib loading, add dyld_lazy_dylib_stub_binding_helper() to live roots
-       if ( fOptions.usingLazyDylibLinking() ) {
-               ObjectFile::Atom* dyldLazyDylibHelper = this->dyldLazyLibraryHelper();
-               if ( dyldLazyDylibHelper != NULL )
-                       fLiveRootAtoms.insert(dyldLazyDylibHelper);
-       }
-       
-       // add -exported_symbols_list, -init, and -u entries to live roots
-       std::vector<const char*>& initialUndefines = fOptions.initialUndefines();
-       for (std::vector<const char*>::iterator it=initialUndefines.begin(); it != initialUndefines.end(); it++)
-               addLiveRoot(*it);
-
-       // if -exported_symbols_list that has wildcards, we need to find all matches and make them the roots 
-       // <rdar://problem/5524973>
-       if ( fOptions.hasWildCardExportRestrictList() ) {
-               for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
-                       ObjectFile::Atom* atom = *it;
-                       if ( (atom->getScope() == ObjectFile::Atom::scopeGlobal) 
-                               && (fDeadAtoms.count(atom) == 0) 
-                               && fOptions.shouldExport(atom->getName()) )
-                                       fLiveRootAtoms.insert(atom);
-               }
-       }
-
-       // in some cases, every global scope atom in initial .o files is a root
-       if ( fOptions.allGlobalsAreDeadStripRoots() ) {
-               for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
-                       ObjectFile::Atom* atom = *it;
-                       if ( (atom->getScope() == ObjectFile::Atom::scopeGlobal) && (fDeadAtoms.count(atom) == 0) )
-                               fLiveRootAtoms.insert(atom);
-               }
-       }
-
-       // mark all roots as live, and all atoms they reference
-       for (std::set<ObjectFile::Atom*>::iterator it=fLiveRootAtoms.begin(); it != fLiveRootAtoms.end(); it++) {
-               WhyLiveBackChain rootChain;
-               rootChain.previous = NULL;
-               rootChain.referer = *it;
-               markLive(**it, &rootChain);
-       }
-
-       // it is possible that there are unresolved references that can be resolved now
-       // this can happen if the first reference to a common symbol in an archive.
-       // common symbols are not in the archive TOC, but the .o could have been pulled in later.
-       // <rdar://problem/4654131> ld64 while linking cc1 [ when dead_strip is ON]
-       for (std::vector<ObjectFile::Atom*>::iterator it=fAtomsWithUnresolvedReferences.begin(); it != fAtomsWithUnresolvedReferences.end(); it++) {
-               std::vector<class ObjectFile::Reference*>& references = (*it)->getReferences();
-               for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
-                       ObjectFile::Reference* reference = *rit;
-                       if ( reference->getTargetBinding() == ObjectFile::Reference::kUnboundByName ) {
-                               ObjectFile::Atom* target = fGlobalSymbolTable.find(reference->getTargetName());
-                               if ( target != NULL ) {
-                                       reference->setTarget(*target, reference->getTargetOffset());
-                                       fLiveAtoms.insert(target);
-                                       // by just adding this atom to fLiveAtoms set, we are assuming it has no
-                                       // references, which is true for commons.
-                                       if ( target->getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition )
-                                               warning("internal error %s is not a tentative definition", target->getDisplayName());
-                               }
-                       }
-                       if ( reference->getFromTargetBinding() == ObjectFile::Reference::kUnboundByName ) {
-                               ObjectFile::Atom* target = fGlobalSymbolTable.find(reference->getFromTargetName());
-                               if ( target != NULL ) {
-                                       reference->setFromTarget(*target);
-                                       fLiveAtoms.insert(target);
-                                       // by just adding this atom to fLiveAtoms set, we are assuming it has no
-                                       // references, which is true for commons.
-                                       if ( target->getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition )
-                                               warning("internal error %s is not a tentative definition", target->getDisplayName());
-                               }
-                       }
-               }
-       }
-
-       // It is possible that some weak symbols were overridden by lazily load objects from archives
-       // and we have some atoms that still refer to the overridden ones.
-       // In that case we need to go back and rebind
-       if ( fAtomsOverriddenByLateLoads.size() > 0 ) {
-               for (std::set<ObjectFile::Atom*>::iterator it=fLiveAtoms.begin(); it != fLiveAtoms.end(); ++it) {
-                       ObjectFile::Atom* atom = *it;
-                       std::vector<class ObjectFile::Reference*>& references = atom->getReferences();
-                       for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); ++rit) {
-                               ObjectFile::Reference* reference = *rit;
-                               ObjectFile::Atom* toTarget = &reference->getTarget();
-                               if ( fAtomsOverriddenByLateLoads.count(toTarget) ) {
-                                       //fprintf(stderr, "change reference in %p from %p to %p\n", atom, toTarget, fGlobalSymbolTable.find(toTarget->getName()));
-                                       reference->setTarget(*fGlobalSymbolTable.find(toTarget->getName()), reference->getTargetOffset());
-                               }
-                               ObjectFile::Atom* fromTarget = &reference->getFromTarget();
-                               if ( (fromTarget != NULL) && fAtomsOverriddenByLateLoads.count(fromTarget) ) {
-                                       //fprintf(stderr, "change from reference in %p from %p to %p\n", atom, fromTarget, fGlobalSymbolTable.find(fromTarget->getName()));
-                                       reference->setTarget(*fGlobalSymbolTable.find(fromTarget->getName()), reference->getFromTargetOffset());
-                               }
-                       }
-               }
-
-               // make sure overriders are live if the atom they overrid was live
-               for (std::set<ObjectFile::Atom*>::iterator it=fAtomsOverriddenByLateLoads.begin(); it != fAtomsOverriddenByLateLoads.end(); ++it) {
-                       ObjectFile::Atom* overriderAtom = *it;
-                       if ( fLiveAtoms.count(overriderAtom) ) {
-                               WhyLiveBackChain rootChain;
-                               rootChain.previous = NULL;
-                               rootChain.referer = *it;
-                               markLive(*fGlobalSymbolTable.find(overriderAtom->getName()), &rootChain);
-                       }
-               }
-
-               // remove overridden atoms from fLiveAtoms
-               fAllAtoms.erase(std::remove_if(fAllAtoms.begin(), fAllAtoms.end(), InSet(fAtomsOverriddenByLateLoads)), fAllAtoms.end());
-               fAtomsOverriddenByLateLoads.clear();
-               // remove dead atoms from fLiveAtoms
-               fAllAtoms.erase(std::remove_if(fAllAtoms.begin(), fAllAtoms.end(), InSet(fDeadAtoms)), fAllAtoms.end());
-       }
-       
-       // now remove all non-live atoms from fAllAtoms
-       fAllAtoms.erase(std::remove_if(fAllAtoms.begin(), fAllAtoms.end(), NotLive(fLiveAtoms)), fAllAtoms.end());
-}
-
-void Linker::checkObjC()
-{
-       // check dylibs
-       switch ( fCurrentObjCConstraint ) {
-               case ObjectFile::Reader::kObjcNone:
-                       // can link against any dylib
-                       break;
-               case ObjectFile::Reader::kObjcRetainRelease:
-                       // cannot link against GC-only dylibs
-                       for (InstallNameToReader::iterator it=fDylibMap.begin(); it != fDylibMap.end(); it++) {
-                               if ( it->second->explicitlyLinked() ) {
-                                       if ( it->second->getObjCConstraint() == ObjectFile::Reader::kObjcGC )
-                                               throwf("this linkage unit uses Retain/Release.  It cannot link against the GC-only dylib: %s", it->second->getPath());
-                               }
-                       }
-                       break;
-               case ObjectFile::Reader::kObjcRetainReleaseOrGC:
-                       // can link against GC or RR dylibs
-                       break;
-               case ObjectFile::Reader::kObjcGC:
-                       // cannot link against RR-only dylibs
-                       for (InstallNameToReader::iterator it=fDylibMap.begin(); it != fDylibMap.end(); it++) {
-                               if ( it->second->explicitlyLinked() ) {
-                                       if ( it->second->getObjCConstraint() == ObjectFile::Reader::kObjcRetainRelease )
-                                               throwf("this linkage unit requires GC.  It cannot link against Retain/Release dylib: %s", it->second->getPath());
-                               }
-                       }
-                       break;
-       }
-       
-       // synthesize __OBJC __image_info atom if needed
-       if ( fCurrentObjCConstraint != ObjectFile::Reader::kObjcNone ) {
-               this->addAtom(fOutputFile->makeObjcInfoAtom(fCurrentObjCConstraint, fObjcReplacmentClasses));
-       }
-}
-
-
-static uint8_t pcRelKind(cpu_type_t arch)
-{
-       switch ( arch ) {
-               case CPU_TYPE_POWERPC:
-                       return ppc::kPointerDiff32;
-               case CPU_TYPE_POWERPC64:
-                       return ppc64::kPointerDiff32;
-               case CPU_TYPE_I386:
-                       return x86::kPointerDiff;
-               case CPU_TYPE_X86_64:
-                       return x86_64::kPointerDiff32;
-               case CPU_TYPE_ARM:
-                       return arm::kPointerDiff;
-       }
-       throw "uknown architecture";
-}
-
-typedef uint8_t* (*oldcreatedof_func_t) (const char*, cpu_type_t, unsigned int, const char*[], const char*[], uint64_t offsetsInDOF[], size_t* size);
-typedef uint8_t* (*createdof_func_t)(cpu_type_t, unsigned int, const char*[], unsigned int, const char*[], const char*[], uint64_t offsetsInDOF[], size_t* size);
-
-
-void Linker::processDTrace()
-{
-       // only make __dof section in final linked images
-       if ( fOptions.outputKind() == Options::kObjectFile )
-               return;
-
-       // scan all atoms looking for dtrace probes
-       std::vector<DTraceProbeInfo>                                            probeSites;
-       std::vector<DTraceProbeInfo>                                            isEnabledSites;
-       std::map<const ObjectFile::Atom*,CStringSet>            atomToDtraceTypes;
-       for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); ++it) {
-               ObjectFile::Atom* atom = *it;
-               std::vector<class ObjectFile::Reference*>& references = atom->getReferences();
-               for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); ++rit) {
-                       ObjectFile::Reference* ref = *rit;
-                       if ( ref->getTargetBinding() == ObjectFile::Reference::kDontBind ) {
-                               const char* probeName = ref->getTargetName();
-                               if ( probeName != NULL ) {
-                                       uint32_t offsetInAtom = ref->getFixUpOffset();
-                                       if ( strncmp(probeName, "___dtrace_probe$", 16) == 0 ) 
-                                               probeSites.push_back(DTraceProbeInfo(atom, offsetInAtom, probeName));
-                                       else if ( strncmp(probeName, "___dtrace_isenabled$", 20) == 0 ) 
-                                               isEnabledSites.push_back(DTraceProbeInfo(atom, offsetInAtom, probeName));
-                                       else if ( strncmp(probeName, "___dtrace_", 10) == 0 )
-                                               atomToDtraceTypes[atom].insert(probeName);
-                               }
-                       }
-               }
-       }
-
-       // if no probes, we're done
-       if ( (probeSites.size() == 0) && (isEnabledSites.size() == 0) ) 
-               return;
-       
-       // partition probes by provider name
-       // The symbol names looks like:
-       //      "___dtrace_probe$" provider-name "$" probe-name [ "$"... ]
-       //      "___dtrace_isenabled$" provider-name "$" probe-name [ "$"... ]
-       ProviderToProbes providerToProbes;
-       std::vector<DTraceProbeInfo> emptyList;
-       for(std::vector<DTraceProbeInfo>::iterator it = probeSites.begin(); it != probeSites.end(); ++it) {
-               // ignore probes in functions that were coalesed away rdar://problem/5628149
-               if ( fDeadAtoms.count((ObjectFile::Atom*)(it->atom)) == 0 ) {
-                       const char* providerStart = &it->probeName[16];
-                       const char* providerEnd = strchr(providerStart, '$');
-                       if ( providerEnd != NULL ) {
-                               char providerName[providerEnd-providerStart+1];
-                               strlcpy(providerName, providerStart, providerEnd-providerStart+1);
-                               ProviderToProbes::iterator pos = providerToProbes.find(providerName);
-                               if ( pos == providerToProbes.end() ) {
-                                       const char* dup = strdup(providerName);
-                                       providerToProbes[dup] = emptyList;
-                               }
-                               providerToProbes[providerName].push_back(*it);
-                       }
-               }
-       }
-       for(std::vector<DTraceProbeInfo>::iterator it = isEnabledSites.begin(); it != isEnabledSites.end(); ++it) {
-               // ignore probes in functions that were coalesed away rdar://problem/5628149
-               if ( fDeadAtoms.count((ObjectFile::Atom*)(it->atom)) == 0 ) {
-                       const char* providerStart = &it->probeName[20];
-                       const char* providerEnd = strchr(providerStart, '$');
-                       if ( providerEnd != NULL ) {
-                               char providerName[providerEnd-providerStart+1];
-                               strlcpy(providerName, providerStart, providerEnd-providerStart+1);
-                               ProviderToProbes::iterator pos = providerToProbes.find(providerName);
-                               if ( pos == providerToProbes.end() ) {
-                                       const char* dup = strdup(providerName);
-                                       providerToProbes[dup] = emptyList;
-                               }
-                               providerToProbes[providerName].push_back(*it);
-                       }
-               }
-       }
-       
-       // create a DOF section for each provider
-       int dofIndex=1;
-       CStringSet sectionNamesUsed;
-       for(ProviderToProbes::iterator pit = providerToProbes.begin(); pit != providerToProbes.end(); ++pit, ++dofIndex) {
-               const char* providerName = pit->first;
-               const std::vector<DTraceProbeInfo>& probes = pit->second;
-
-               // open library and find dtrace_create_dof()
-               void* handle = dlopen("/usr/lib/libdtrace.dylib", RTLD_LAZY);
-               if ( handle == NULL )
-                       throwf("couldn't dlopen() /usr/lib/libdtrace.dylib: %s", dlerror());
-               createdof_func_t pCreateDOF = (createdof_func_t)dlsym(handle, "dtrace_ld_create_dof");
-               if ( pCreateDOF == NULL )
-                       throwf("couldn't find \"dtrace_ld_create_dof\" in /usr/lib/libdtrace.dylib: %s", dlerror());
-               // build list of typedefs/stability infos for this provider
-               CStringSet types;
-               for(std::vector<DTraceProbeInfo>::const_iterator it = probes.begin(); it != probes.end(); ++it) {
-                       std::map<const ObjectFile::Atom*,CStringSet>::iterator pos = atomToDtraceTypes.find(it->atom);
-                       if ( pos != atomToDtraceTypes.end() ) {
-                               for(CStringSet::iterator sit = pos->second.begin(); sit != pos->second.end(); ++sit) {
-                                       const char* providerStart = strchr(*sit, '$')+1;
-                                       const char* providerEnd = strchr(providerStart, '$');
-                                       if ( providerEnd != NULL ) {
-                                               char aProviderName[providerEnd-providerStart+1];
-                                               strlcpy(aProviderName, providerStart, providerEnd-providerStart+1);
-                                               if ( strcmp(aProviderName, providerName) == 0 )
-                                                       types.insert(*sit);
-                                       }
-                               }
-                       }
-               }
-               int typeCount = types.size();
-               const char* typeNames[typeCount];
-               //fprintf(stderr, "types for %s:\n", providerName);
-               uint32_t index = 0;
-               for(CStringSet::iterator it = types.begin(); it != types.end(); ++it) {
-                       typeNames[index] = *it;
-                       //fprintf(stderr, "\t%s\n", *it);
-                       ++index;
-               }
-               
-               // build list of probe/isenabled sites
-               const uint32_t probeCount = probes.size();
-               const char* probeNames[probeCount];
-               const char* funtionNames[probeCount];
-               uint64_t offsetsInDOF[probeCount];
-               index = 0;
-               for(std::vector<DTraceProbeInfo>::const_iterator it = probes.begin(); it != probes.end(); ++it) {
-                       probeNames[index] = it->probeName;
-                       funtionNames[index] = it->atom->getName();
-                       offsetsInDOF[index] = 0;
-                       ++index;
-               }
-               //fprintf(stderr, "calling libtrace to create DOF\n");
-               //for(uint32_t i=0; i < probeCount; ++i) 
-               //      fprintf(stderr, "  [%u]\t %s\t%s\n", i, probeNames[i], funtionNames[i]);
-               // call dtrace library to create DOF section
-               size_t dofSectionSize;
-               uint8_t* p = (*pCreateDOF)(fArchitecture, typeCount, typeNames, probeCount, probeNames, funtionNames, offsetsInDOF, &dofSectionSize);
-               if ( p != NULL ) {
-                       char sectionName[18];
-                       strcpy(sectionName, "__dof_");
-                       strlcpy(&sectionName[6], providerName, 10);
-                       // create unique section name so each DOF is in its own section
-                       if ( sectionNamesUsed.count(sectionName) != 0 ) {
-                               sectionName[15] = '0';
-                               sectionName[16] = '\0';
-                               while ( sectionNamesUsed.count(sectionName) != 0 )
-                                       ++sectionName[15];
-                       }
-                       sectionNamesUsed.insert(sectionName);
-                       char symbolName[strlen(providerName)+64];
-                       sprintf(symbolName, "__dtrace_dof_for_provider_%s", providerName);
-                       opaque_section::Reader* reader = new opaque_section::Reader("__TEXT", sectionName, 
-                                                                                                       "dtrace", p, dofSectionSize, fNextInputOrdinal, symbolName);
-                       fNextInputOrdinal += dofSectionSize;
-                       // add references
-                       for (uint32_t i=0; i < probeCount; ++i) {
-                               uint64_t offset = offsetsInDOF[i];
-                               //fprintf(stderr, "%s offset[%d]=0x%08llX\n", providerName, i, offset);
-                               if ( offset > dofSectionSize )
-                                       throwf("offsetsInDOF[%d]=%0llX > dofSectionSize=%0lX\n", i, offset, dofSectionSize);
-                               reader->addSectionReference(pcRelKind(fArchitecture), offset, probes[i].atom, probes[i].offset, reader->getAtoms()[0], 0);
-                       }
-                       this->addAtoms(reader->getAtoms());
-               }
-               else {
-                       throw "error creating dtrace DOF section";
-               }
-       }
-}
-
-
-static bool matchesObjectFile(ObjectFile::Atom* atom, const char* objectFileLeafName)
-{
-       if ( objectFileLeafName == NULL )
-               return true;
-       const char* atomFullPath = atom->getFile()->getPath();
-       const char* lastSlash = strrchr(atomFullPath, '/');
-       if ( lastSlash != NULL ) {
-               if ( strcmp(&lastSlash[1], objectFileLeafName) == 0 )
-                       return true;
-       }
-       else {
-               if ( strcmp(atomFullPath, objectFileLeafName) == 0 )
-                       return true;
-       }
-       return false;
-}
-
-
-ObjectFile::Atom* Linker::findAtom(const Options::OrderedSymbol& orderedSymbol)
-{
-       ObjectFile::Atom* atom = fGlobalSymbolTable.find(orderedSymbol.symbolName);
-       if ( atom != NULL ) {
-               if ( matchesObjectFile(atom, orderedSymbol.objectFileName) )
-                       return atom;
-       }
-       else {
-               // slow case.  The requested symbol is not in symbol table, so might be static function
-               static SymbolTable::Mapper hashTableOfTranslationUnitScopedSymbols;
-               static bool built = false;
-               // build a hash_map the first time
-               if ( !built ) {
-                       for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
-                               atom = *it;
-                               const char* name = atom->getName();
-                               if ( name != NULL) {
-                                       if ( atom->getScope() == ObjectFile::Atom::scopeTranslationUnit ) {
-                                               // static function or data
-                                               SymbolTable::Mapper::iterator pos = hashTableOfTranslationUnitScopedSymbols.find(name);
-                                               if ( pos == hashTableOfTranslationUnitScopedSymbols.end() )
-                                                       hashTableOfTranslationUnitScopedSymbols[name] = atom;
-                                               else
-                                                       hashTableOfTranslationUnitScopedSymbols[name] = NULL;   // collision, denote with NULL
-                                       }
-                               }
-                       }
-                       //fprintf(stderr, "built hash table of %lu static functions\n", hashTableOfTranslationUnitScopedSymbols.size());
-                       built = true;
-               }
-
-               // look for name in hashTableOfTranslationUnitScopedSymbols
-               SymbolTable::Mapper::iterator pos = hashTableOfTranslationUnitScopedSymbols.find(orderedSymbol.symbolName);
-               if ( pos != hashTableOfTranslationUnitScopedSymbols.end() ) {
-                       if ( (pos->second != NULL) && matchesObjectFile(pos->second, orderedSymbol.objectFileName) ) {
-                               //fprintf(stderr, "found %s in hash table\n", orderedSymbol.symbolName);
-                               return pos->second;
-                       }
-                       if ( pos->second == NULL )
-                       // name is in hash table, but atom is NULL, so that means there are duplicates, so we use super slow way
-                       for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
-                               atom = *it;
-                               if ( atom->getScope() == ObjectFile::Atom::scopeTranslationUnit ) {
-                                       const char* name = atom->getName();
-                                       if ( (name != NULL) && (strcmp(name, orderedSymbol.symbolName) == 0) ) {
-                                               if ( matchesObjectFile(atom, orderedSymbol.objectFileName) ) {
-                                                       if ( fOptions.printOrderFileStatistics() )
-                                                               warning("%s specified in order_file but it exists in multiple .o files. "
-                                                                               "Prefix symbol with .o filename in order_file to disambiguate", orderedSymbol.symbolName);
-                                                       return atom;
-                                               }
-                                       }
-                               }
-                       }
-               }
-               
-       }
-       return NULL;
-}
-
-
-void Linker::sortSections()
-{
-       Section::assignIndexes(fOptions.outputKind() == Options::kObjectFile);
-}
-
-
-//
-// Linker::sortAtoms()
-//
-// The purpose of this method is to take the graph of all Atoms and produce an ordered
-// sequence of atoms.  The constraints are that: 1) all Atoms of the same Segment must
-// be contiguous, 2)  all Atoms of the same Section must be contigous, 3) Atoms specified
-// in an order_file are seqenced as in the order_file and before Atoms not specified,
-// 4) Atoms in the same section from the same .o file should be contiguous and sequenced
-// in the same order they were in the .o file, 5) Atoms in the same Section but which came
-// from different .o files should be sequenced in the same order that the .o files
-// were passed to the linker (i.e. command line order).
-//
-// The way this is implemented is that the linker passes a "base ordinal" to each Reader
-// as it is constructed.  The reader should construct it Atoms so that calling getOrdinal()
-// on its atoms returns a contiguous range of values starting at the base ordinal.  Then
-// sorting is just sorting by section, then by ordinal.
-//
-// If an order_file is specified, it gets more complicated.  First, an override-ordinal map
-// is created.  It causes the sort routine to ignore the value returned by getOrdinal() and
-// use the override value instead.  Next some Atoms must be layed out consecutively
-// (e.g. hand written assembly that does not end with return, but rather falls into
-// the next label).  This is modeled in Readers via a "kFollowOn" reference.  The use of
-// kFollowOn refernces produces "clusters" of atoms that must stay together.
-// If an order_file tries to move one atom, it may need to move a whole cluster.  The
-// algorithm to do this models clusters using two maps.  The "starts" maps maps any
-// atom in a cluster to the first Atom in the cluster.  The "nexts" maps an Atom in a
-// cluster to the next Atom in the cluster.  With this in place, while processing an
-// order_file, if any entry is in a cluster (in "starts" map), then the entire cluster is
-// given ordinal overrides.
-//
-void Linker::sortAtoms()
-{
-       fStartSortTime = mach_absolute_time();
-       // if -order_file is used, build map of atom ordinal overrides
-       std::map<const ObjectFile::Atom*, uint32_t>* ordinalOverrideMap = NULL;
-       std::map<const ObjectFile::Atom*, uint32_t> theOrdinalOverrideMap;
-       const bool log = false;
-       if ( fOptions.orderedSymbols().size() != 0 ) {
-               // first make a pass to find all follow-on references and build start/next maps
-               // which are a way to represent clusters of atoms that must layout together
-               std::map<const ObjectFile::Atom*, const ObjectFile::Atom*> followOnStarts;
-               std::map<const ObjectFile::Atom*, const ObjectFile::Atom*> followOnNexts;
-               for (std::vector<ObjectFile::Atom*>::iterator ait=fAllAtoms.begin(); ait != fAllAtoms.end(); ait++) {
-                       ObjectFile::Atom* atom = *ait;
-                       std::vector<class ObjectFile::Reference*>& references = atom->getReferences();
-                       for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
-                               ObjectFile::Reference* ref = *rit;
-                               if ( ref->getKind() == 1 ) {    // FIX FIX
-                                       ObjectFile::Atom* targetAtom = &ref->getTarget();
-                                       if ( log ) fprintf(stderr, "ref %s -> %s", atom->getDisplayName(), targetAtom->getDisplayName());
-                                       std::map<const ObjectFile::Atom*, const ObjectFile::Atom*>::iterator startFrom = followOnStarts.find(atom);
-                                       std::map<const ObjectFile::Atom*, const ObjectFile::Atom*>::iterator startTo = followOnStarts.find(targetAtom);
-                                       if ( (startFrom == followOnStarts.end()) && (startTo == followOnStarts.end()) ) {
-                                               // this is first time we've seen either atom, make simple cluster of the two
-                                               if ( log ) fprintf(stderr, "  new cluster\n");
-                                               followOnStarts[atom] = atom;
-                                               followOnStarts[targetAtom] = atom;
-                                               followOnNexts[atom] = targetAtom;
-                                               followOnNexts[targetAtom] = NULL;
-                                       }
-                                       else if ( (startFrom != followOnStarts.end()) && (startTo == followOnStarts.end()) && (followOnNexts[atom] == NULL) ) {
-                                               // atom is at end of an existing cluster, so append target to end of cluster
-                                               if ( log ) fprintf(stderr, "  end of cluster starting with %s\n", followOnStarts[atom]->getDisplayName());
-                                               followOnNexts[atom] = targetAtom;
-                                               followOnNexts[targetAtom] = NULL;
-                                               followOnStarts[targetAtom] = followOnStarts[atom];
-                                       }
-                                       else {
-                                               // gerneral case of inserting into an existing cluster
-                                               if ( followOnNexts[atom] != NULL ) {
-                                                       // an atom with two follow-ons is illegal
-                                                       warning("can't order %s because both %s and %s must follow it",
-                                                                               atom->getDisplayName(), targetAtom->getDisplayName(), followOnNexts[atom]->getDisplayName());
-                                               }
-                                               else {
-                                                       // there already exists an atom that says target must be its follow-on
-                                                       const ObjectFile::Atom* originalStart = startTo->second;
-                                                       const ObjectFile::Atom* originalPrevious = originalStart;
-                                                       while ( followOnNexts[originalPrevious] != targetAtom )
-                                                               originalPrevious = followOnNexts[originalPrevious];
-                                                       bool otherIsAlias = (originalPrevious->getSize() == 0);
-                                                       bool thisIsAlias = (atom->getSize() == 0);
-                                                       if ( !otherIsAlias && !thisIsAlias ) {
-                                                               warning("can't order %s because both %s and %s must preceed it",
-                                                                                       targetAtom->getDisplayName(), originalPrevious->getDisplayName(), atom->getDisplayName());
-                                                       }
-                                                       else if ( otherIsAlias ) {
-                                                               if ( originalPrevious == originalStart ) {
-                                                                       // other is alias at start of cluster, make this the new start of cluster
-                                                                       if ( log ) fprintf(stderr, "  becomes new start of cluster previous starting with %s\n", originalStart->getDisplayName());
-                                                                       followOnNexts[atom] = originalPrevious;
-                                                                       for(const ObjectFile::Atom* nextAtom = atom; nextAtom != NULL; nextAtom = followOnNexts[nextAtom])
-                                                                               followOnStarts[nextAtom] = atom;
-                                                               }
-                                                               else {
-                                                                       // other is alias in middle of cluster, insert new atom before it
-                                                                       if ( log ) fprintf(stderr, "  insert into cluster starting with %s before alias %s\n", originalStart->getDisplayName(), originalPrevious->getDisplayName());
-                                                                       followOnStarts[atom] = originalStart;
-                                                                       followOnNexts[atom] = originalPrevious;
-                                                                       for(const ObjectFile::Atom* a = originalStart; a != NULL; a = followOnNexts[a]) {
-                                                                               if ( followOnNexts[a] == originalPrevious ) {
-                                                                                       followOnNexts[a] = atom;
-                                                                                       break;
-                                                                               }
-                                                                       }
-                                                               }
-                                                       }
-                                                       else {
-                                                               // this is alias, so it can go inbetween originalPrevious and targetAtom
-                                                               if ( log ) fprintf(stderr, "  insert into cluster starting with %s after %s\n", originalStart->getDisplayName(), originalPrevious->getDisplayName());
-                                                               followOnStarts[atom] = originalStart;
-                                                               followOnNexts[atom] = followOnNexts[originalPrevious];
-                                                               followOnNexts[originalPrevious] = atom;
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               }
-
-               if ( log ) {
-                       for(std::map<const ObjectFile::Atom*, const ObjectFile::Atom*>::iterator it = followOnStarts.begin(); it != followOnStarts.end(); ++it)
-                               fprintf(stderr, "start %s -> %s\n", it->first->getDisplayName(), it->second->getDisplayName());
-
-                       for(std::map<const ObjectFile::Atom*, const ObjectFile::Atom*>::iterator it = followOnNexts.begin(); it != followOnNexts.end(); ++it)
-                               fprintf(stderr, "next %s -> %s\n", it->first->getDisplayName(), (it->second != NULL) ? it->second->getDisplayName() : "null");
-               }
-
-               // with the start/next maps of follow-on atoms we can process the order file and produce override ordinals
-               ordinalOverrideMap = &theOrdinalOverrideMap;
-               uint32_t index = 0;
-               uint32_t matchCount = 0;
-               std::vector<Options::OrderedSymbol>& orderedSymbols = fOptions.orderedSymbols();
-               for(std::vector<Options::OrderedSymbol>::iterator it = orderedSymbols.begin(); it != orderedSymbols.end(); ++it) {
-                       ObjectFile::Atom* atom = this->findAtom(*it);
-                       if ( atom != NULL ) {
-                               std::map<const ObjectFile::Atom*, const ObjectFile::Atom*>::iterator start = followOnStarts.find(atom);
-                               if ( start != followOnStarts.end() ) {
-                                       // this symbol for the order file corresponds to an atom that is in a cluster that must lay out together
-                                       for(const ObjectFile::Atom* nextAtom = start->second; nextAtom != NULL; nextAtom = followOnNexts[nextAtom]) {
-                                               std::map<const ObjectFile::Atom*, uint32_t>::iterator pos = theOrdinalOverrideMap.find(nextAtom);
-                                               if ( pos == theOrdinalOverrideMap.end() ) {
-                                                       theOrdinalOverrideMap[nextAtom] = index++;
-                                                       if (log ) fprintf(stderr, "override ordinal %u assigned to %s in cluster from %s\n", index, nextAtom->getDisplayName(), nextAtom->getFile()->getPath());
-                                               }
-                                               else {
-                                                       if (log ) fprintf(stderr, "could not order %s as %u because it was already laid out earlier by %s as %u\n",
-                                                                                       atom->getDisplayName(), index, followOnStarts[atom]->getDisplayName(), theOrdinalOverrideMap[atom] );
-                                               }
-                                       }
-                               }
-                               else {
-                                       theOrdinalOverrideMap[atom] = index;
-                                       if (log ) fprintf(stderr, "override ordinal %u assigned to %s from %s\n", index, atom->getDisplayName(), atom->getFile()->getPath());
-                               }
-                               ++matchCount;
-                       }
-                       else {
-                               if ( fOptions.printOrderFileStatistics() ) {
-                                       if ( it->objectFileName == NULL )
-                                               warning("can't find match for order_file entry: %s", it->symbolName);
-                                       else
-                                               warning("can't find match for order_file entry: %s/%s", it->objectFileName, it->symbolName);
-                               }
-                       }
-                        ++index;
-               }
-               if ( fOptions.printOrderFileStatistics() && (fOptions.orderedSymbols().size() != matchCount) ) {
-                       warning("only %u out of %lu order_file symbols were applicable", matchCount, fOptions.orderedSymbols().size() );
-               }
-       }
-
-       // sort atoms
-       std::sort(fAllAtoms.begin(), fAllAtoms.end(), Linker::AtomSorter(ordinalOverrideMap, fInitializerAtoms, fTerminatorAtoms));
-
-       //fprintf(stderr, "Sorted atoms:\n");
-       //for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
-       //      fprintf(stderr, "\t%s, %u  %s\t%s\n", (*it)->getSectionName(), (*it)->getSection()->getIndex(), (*it)->getDisplayName(), (*it)->getFile()->getPath());
-       //}
-}
-
-
-// make sure given addresses are within reach of branches, etc
-void Linker::tweakLayout()
-{
-       // > 2GB images need their large zero fill atoms sorted to the end to keep access with +/- 2GB
-       if ( fTotalSize > 0x7F000000 ) {
-               fBiggerThanTwoGigOutput = true;
-
-               if ( (fTotalSize-fTotalZeroFillSize) > 0x7F000000 )
-                       throwf("total output size exceeds 2GB (%lldMB)", (fTotalSize-fTotalZeroFillSize)/(1024*1024));          
-
-               // move very large (>1MB) zero fill atoms to a new section at very end of __DATA segment
-               Section* hugeZeroFills = Section::find("__huge", "__DATA", true, true);
-               for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
-                       ObjectFile::Atom* atom = *it;
-                       if ( atom->isZeroFill() && (atom->getSize() > 1024*1024) && (strcmp(atom->getSegment().getName(), "__DATA") == 0) )
-                               atom->setSection(hugeZeroFills);
-               }
-       }
-       
-       // move all initializers to start of __text section
-       if ( fOptions.readerOptions().fAutoOrderInitializers ) {
-               // move -init function to front of __text
-               if ( fOptions.initFunctionName() != NULL ) {
-                       ObjectFile::Atom* initAtom = fGlobalSymbolTable.find(fOptions.initFunctionName());
-                       if ( initAtom == NULL )
-                               throwf("could not find -init function: \"%s\"", fOptions.initFunctionName());
-                       moveToFrontOfSection(initAtom);
-               }
-               
-               // move all functions pointed to by __mod_init_func section to front of __text
-               Section* initSection = Section::find("__mod_init_func", "__DATA", false, true, false);
-               if ( initSection != NULL ) {
-                       for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); ++it) {
-                               if ( (*it)->getSection() == initSection ) {
-                                       std::vector<class ObjectFile::Reference*>& references = (*it)->getReferences();
-                                       if ( references.size() == 1 ) 
-                                               moveToFrontOfSection(&(references[0]->getTarget()));
-                               }
-                       }
-               }
-       }
-       
-       // move atoms with relocations to start of __DATA,__data section
-       // <rdar://problem/6061558> linker should order __DATA segment to reduce dyld dirtied pages
-       if ( fOptions.orderData() ) {
-               bool slideable = false;
-               switch ( fOptions.outputKind() ) {
-                       case Options::kDynamicExecutable:
-                       case Options::kStaticExecutable:
-                       case Options::kDyld:
-                       case Options::kPreload:
-                       case Options::kObjectFile:
-                       case Options::kKextBundle:
-                               slideable = false;
-                               break;
-                       case Options::kDynamicLibrary:
-                       case Options::kDynamicBundle:
-                               slideable = true;
-                               break;
-               }
-               const bool hasPreferredLoadAddress = (fOptions.baseAddress() != 0);
-               Section* dataSection = Section::find("__data", "__DATA", false, true, false);
-               if ( dataSection != NULL ) {
-                       for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); ++it) {
-                               ObjectFile::Atom* dataAtom = *it;
-                               if ( dataAtom->getSection() == dataSection ) {
-                                       std::vector<class ObjectFile::Reference*>& references = dataAtom->getReferences();
-                                       if ( references.size() > 0 ) {
-                                               if ( slideable && !hasPreferredLoadAddress ) {
-                                                       // in a slidable image dyld will need to rebase and bind so any references will need runtime fixups
-                                                       // if image has preferred base address, assume it will load there and not rebase
-                                                       moveToFrontOfSection(dataAtom);
-                                               }
-                                               else {
-                                                       // in a non-slideable image, dyld will only do binding, so only references to
-                                                       // symbols in another dylib will need runtime fixups
-                                                       //fprintf(stderr, "reference from atom %s\n", dataAtom->getDisplayName());
-                                                       for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
-                                                               ObjectFile::Reference* reference = *rit;
-                                                               //fprintf(stderr, "\t%d %s\n", reference->getTarget().getDefinitionKind(), reference->getTarget().getDisplayName());
-                                                               if ( (reference->getTarget().getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
-                                                                 || (reference->getTarget().getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
-                                                                       moveToFrontOfSection(dataAtom);
-                                                                       break;
-                                                               }
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               }
-       }
-       
-}
-
-
-void Linker::writeDotOutput()
-{
-       const char* dotOutFilePath = fOptions.dotOutputFile();
-       if ( dotOutFilePath != NULL ) {
-               FILE* out = fopen(dotOutFilePath, "w");
-               if ( out != NULL ) {
-                       // print header
-                       fprintf(out, "digraph dg\n{\n");
-                       fprintf(out, "\tconcentrate = true;\n");
-                       fprintf(out, "\trankdir = LR;\n");
-
-                       // print each atom as a node
-                       for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
-                               ObjectFile::Atom* atom = *it;
-                               if ( atom->getFile() != fOutputFile ) {
-                                       const char* name = atom->getDisplayName();
-                                       if ( (atom->getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
-                                         || (atom->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
-                                               fprintf(out, "\taddr%p [ shape = plaintext, label = \"%s\" ];\n", atom, name);
-                                       }
-                                       else if ( strcmp(atom->getSectionName(), "__cstring") == 0 ) {
-                                               char cstring[atom->getSize()+2];
-                                               atom->copyRawContent((uint8_t*)cstring);
-                                               fprintf(out, "\taddr%p [ label = \"string: '", atom);
-                                               for (const char* s=cstring; *s != '\0'; ++s) {
-                                                       if ( *s == '\n' )
-                                                               fprintf(out, "\\\\n");
-                                                       else
-                                                               fputc(*s, out);
-                                               }
-                                               fprintf(out, "'\" ];\n");
-                                       }
-                                       else {
-                                               fprintf(out, "\taddr%p [ label = \"%s\" ];\n", atom, name);
-                                       }
-                               }
-                       }
-                       fprintf(out, "\n");
-
-                       // print each reference as an edge
-                       for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
-                               ObjectFile::Atom* fromAtom = *it;
-                               if ( fromAtom->getFile() != fOutputFile ) {
-                                       std::vector<ObjectFile::Reference*>&  references = fromAtom->getReferences();
-                                       std::set<ObjectFile::Atom*> seenTargets;
-                                       for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
-                                               ObjectFile::Reference* reference = *rit;
-                                               ObjectFile::Atom* toAtom = &(reference->getTarget());
-                                               if ( seenTargets.count(toAtom) == 0 ) {
-                                                       seenTargets.insert(toAtom);
-                                                       fprintf(out, "\taddr%p -> addr%p;\n", fromAtom, toAtom);
-                                               }
-                                       }
-                               }
-                       }
-                       fprintf(out, "\n");
-
-                       // push all imports to bottom of graph
-                       fprintf(out, "{ rank = same; ");
-                       for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
-                               ObjectFile::Atom* atom = *it;
-                               if ( atom->getFile() != fOutputFile )
-                                       if ( (atom->getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
-                                         || (atom->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
-                                               fprintf(out, "addr%p; ", atom);
-                                       }
-                       }
-                       fprintf(out, "};\n ");
-
-                       // print footer
-                       fprintf(out, "}\n");
-                       fclose(out);
-               }
-               else {
-                       warning("could not write dot output file: %s", dotOutFilePath);
-               }
-       }
-}
-
-ObjectFile::Atom* Linker::entryPoint(bool orInit, bool searchArchives)
-{
-       // if main executable, find entry point atom
-       ObjectFile::Atom* entryPoint = NULL;
-       switch ( fOptions.outputKind() ) {
-               case Options::kDynamicExecutable:
-               case Options::kStaticExecutable:
-               case Options::kDyld:
-               case Options::kPreload:
-                       entryPoint = fGlobalSymbolTable.find(fOptions.entryName());
-                       if ( (entryPoint == NULL) && searchArchives ) {
-                               // <rdar://problem/7043256> ld64 can not find a -e entry point from an archive                          
-                               this->addJustInTimeAtoms(fOptions.entryName(), false, true, false);
-                               entryPoint = fGlobalSymbolTable.find(fOptions.entryName());
-                       }
-                       if ( entryPoint == NULL ) {
-                               throwf("could not find entry point \"%s\" (perhaps missing crt1.o)", fOptions.entryName());
-                       }
-                       break;
-               case Options::kDynamicLibrary:
-                       if ( orInit && (fOptions.initFunctionName() != NULL) ) {
-                               entryPoint = fGlobalSymbolTable.find(fOptions.initFunctionName());
-                               if ( entryPoint == NULL ) {
-                                       throwf("could not find -init function: \"%s\"", fOptions.initFunctionName());
-                               }
-                       }
-                       break;
-               case Options::kObjectFile:
-               case Options::kDynamicBundle:
-               case Options::kKextBundle:
-                       entryPoint = NULL;
-                       break;
-       }
-       return entryPoint;
-}
-
-ObjectFile::Atom* Linker::dyldClassicHelper()
-{
-       if ( fOptions.makeClassicDyldInfo() )
-               return fGlobalSymbolTable.find("dyld_stub_binding_helper"); 
-       else
-               return NULL;
-}
-
-ObjectFile::Atom* Linker::dyldCompressedHelper()
-{
-       if ( fOptions.makeCompressedDyldInfo() ) {
-               // dyld_stub_binder is in libSystem.B.dylib 
-               ObjectFile::Atom* atom = fGlobalSymbolTable.find("dyld_stub_binder"); 
-               if ( atom == NULL ) {
-                       this->addJustInTimeAtoms("dyld_stub_binder", true, false, true);
-               }
-               atom = fGlobalSymbolTable.find("dyld_stub_binder");
-               return atom;
-       }
-       else
-               return NULL;
-}
-
-ObjectFile::Atom* Linker::dyldLazyLibraryHelper()
-{
-       return fGlobalSymbolTable.find("dyld_lazy_dylib_stub_binding_helper");
-}
-
-const char* Linker::assureFullPath(const char* path)
-{
-       if ( path[0] == '/' )
-               return path;
-       char cwdbuff[MAXPATHLEN];
-       if ( getcwd(cwdbuff, MAXPATHLEN) != NULL ) {
-               char* result;
-               asprintf(&result, "%s/%s", cwdbuff, path);
-               if ( result != NULL )
-                       return result;
-       }
-       return path;
-}
-
-
-//
-// The stab strings are of the form:
-//             <name> ':' <type-code> <number-pari>
-//  but the <name> contain a colon.
-//  For C++ <name> may contain a double colon (e.g. std::string:f(0,1) )
-//  For Objective-C name may contain a colon instead square bracket (e.g. [Foo doit:]:f(0,1) )
-//
-const char* Linker::truncateStabString(const char* str)
-{
-       enum { start, inObjc } state = start;
-       for (const char* s = str; *s != 0; ++s) {
-               char c = *s;
-               switch (state) {
-                       case start:
-                               if ( c == '[' ) {
-                                       state = inObjc;
-                               }
-                               else {
-                                       if ( c == ':' ) {
-                                               if ( s[1] == ':' ) {
-                                                       ++s;
-                                               }
-                                               else {
-                                                       // found colon
-                                                       // Duplicate strndup behavior here.
-                                                       int trunStrLen = s-str+2;
-                                                       char* temp = new char[trunStrLen+1];
-                                                       memcpy(temp, str, trunStrLen);
-                                                       temp[trunStrLen] = '\0';
-                                                       return temp;
-                                               }
-                                       }
-                               }
-                               break;
-                       case inObjc:
-                               if ( c == ']' ) {
-                                       state = start;
-                               }
-                               break;
-               }
-       }
-       // malformed
-       return str;
-}
-
-
-bool Linker::minimizeStab(ObjectFile::Reader::Stab& stab)
-{
-       switch(stab.type){
-               case N_GSYM:
-               case N_STSYM:
-               case N_LCSYM:
-               case N_FUN:
-                       // these all need truncated strings
-                       stab.string = truncateStabString(stab.string);
-                       return true;
-               case N_SO:
-               case N_OSO:
-               case N_OPT:
-               case N_SOL:
-                       // these are included in the minimal stabs, but they keep their full string
-                       return true;
-               default:
-                       return false;
-       }
-}
-
-
-struct HeaderRange {
-       std::vector<ObjectFile::Reader::Stab>::iterator begin;
-       std::vector<ObjectFile::Reader::Stab>::iterator end;
-       int                                                                                             parentRangeIndex;
-       uint32_t                                                                                sum;
-       bool                                                                                    sumPrecomputed;
-       bool                                                                                    useEXCL;
-       bool                                                                                    cannotEXCL; // because of SLINE, etc stabs
-};
-
-
-typedef __gnu_cxx::hash_map<const char*, std::vector<uint32_t>, __gnu_cxx::hash<const char*>, CStringEquals> PathToSums;
-
-// hash table that maps header path to a vector of known checksums for that path
-static PathToSums sKnownBINCLs;
-
-
-void Linker::collectStabs(ObjectFile::Reader* reader, std::map<const class ObjectFile::Atom*, uint32_t>& atomOrdinals)
-{
-       const bool log = false;
-       bool minimal = ( fOptions.readerOptions().fDebugInfoStripping == ObjectFile::ReaderOptions::kDebugInfoMinimal );
-       std::vector<class ObjectFile::Reader::Stab>* readerStabs = reader->getStabs();
-       if ( readerStabs == NULL )
-               return;
-
-       if ( log ) fprintf(stderr, "processesing %lu stabs for %s\n", readerStabs->size(), reader->getPath());
-       std::vector<HeaderRange> ranges;
-       int curRangeIndex = -1;
-       int count = 0;
-       ObjectFile::Atom* atomWithLowestOrdinal = NULL;
-       ObjectFile::Atom* atomWithHighestOrdinal = NULL;
-       uint32_t highestOrdinal = 0;
-       uint32_t lowestOrdinal = UINT_MAX;
-       std::vector<std::pair<ObjectFile::Atom*,ObjectFile::Atom*> > soRanges;
-       // 1) find all (possibly nested) BINCL/EINCL ranges and their checksums
-       // 2) find all SO/SO ranges and the first/last atom own by a FUN stab therein
-       for(std::vector<class ObjectFile::Reader::Stab>::iterator it=readerStabs->begin(); it != readerStabs->end(); ++it) {
-               ++count;
-               switch ( it->type ) {
-                       case N_BINCL:
-                               {
-                                       HeaderRange range;
-                                       range.begin = it;
-                                       range.end = readerStabs->end();
-                                       range.parentRangeIndex = curRangeIndex;
-                                       range.sum = it->value;
-                                       range.sumPrecomputed = (range.sum != 0);
-                                       range.useEXCL = false;
-                                       range.cannotEXCL = false;
-                                       curRangeIndex = ranges.size();
-                                       if ( log ) fprintf(stderr, "[%d]BINCL %s\n", curRangeIndex, it->string);
-                                       ranges.push_back(range);
-                               }
-                               break;
-                       case N_EINCL:
-                               if ( curRangeIndex == -1 ) {
-                                       warning("EINCL missing BINCL in %s", reader->getPath());
-                               }
-                               else {
-                                       ranges[curRangeIndex].end = it+1;
-                                       if ( log ) fprintf(stderr, "[%d->%d]EINCL %s\n", curRangeIndex, ranges[curRangeIndex].parentRangeIndex, it->string);
-                                       curRangeIndex = ranges[curRangeIndex].parentRangeIndex;
-                               }
-                               break;
-                       case N_FUN:
-                               {
-                                       std::map<const class ObjectFile::Atom*, uint32_t>::iterator pos = atomOrdinals.find(it->atom);
-                                       if ( pos != atomOrdinals.end() ) {
-                                               uint32_t ordinal = pos->second;
-                                               if ( ordinal > highestOrdinal ) {
-                                                       highestOrdinal = ordinal;
-                                                       atomWithHighestOrdinal = it->atom;
-                                               }
-                                               if ( ordinal < lowestOrdinal ) {
-                                                       lowestOrdinal = ordinal;
-                                                       atomWithLowestOrdinal = it->atom;
-                                               }
-                                       }
-                               }
-                               // fall through
-                       case N_BNSYM:
-                       case N_ENSYM:
-                       case N_LBRAC:
-                       case N_RBRAC:
-                       case N_SLINE:
-                       case N_STSYM:
-                       case N_LCSYM:
-                               if ( curRangeIndex != -1 ) {
-                                       ranges[curRangeIndex].cannotEXCL = true;
-                                       if ( fOptions.warnStabs() )
-                                               warning("cannot do BINCL/EINCL optimzation because of stabs kinds in %s for %s\n", ranges[curRangeIndex].begin->string, reader->getPath());
-                               }
-                               break;
-                       case N_SO:
-                               if ( (it->string != NULL) && (strlen(it->string) > 0) ) {
-                                       // start SO, reset hi/low FUN tracking
-                                       atomWithLowestOrdinal = NULL;
-                                       atomWithHighestOrdinal = NULL;
-                                       highestOrdinal = 0;
-                                       lowestOrdinal = UINT_MAX;
-                               }
-                               else {
-                                       // end SO, record hi/low atoms for this SO range
-                                       soRanges.push_back(std::make_pair<ObjectFile::Atom*,ObjectFile::Atom*>(atomWithLowestOrdinal, atomWithHighestOrdinal));
-                               }
-                               // fall through
-                       default:
-                               if ( curRangeIndex != -1 ) {
-                                       if ( ! ranges[curRangeIndex].sumPrecomputed ) {
-                                               uint32_t sum = 0;
-                                               const char* s = it->string;
-                                               char c;
-                                               while ( (c = *s++) != 0 ) {
-                                                       sum += c;
-                                                       // don't checkusm first number (file index) after open paren in string
-                                                       if ( c == '(' ) {
-                                                               while(isdigit(*s))
-                                                                       ++s;
-                                                       }
-                                               }
-                                               ranges[curRangeIndex].sum += sum;
-                                       }
-                               }
-
-               }
-       }
-       if ( log ) fprintf(stderr, "processesed %d stabs for %s\n", count, reader->getPath());
-       if ( curRangeIndex != -1 )
-               warning("BINCL (%s) missing EINCL in %s", ranges[curRangeIndex].begin->string, reader->getPath());
-
-       // if no BINCLs
-       if ( ranges.size() == 0 ) {
-               unsigned int soIndex = 0;
-               for(std::vector<ObjectFile::Reader::Stab>::iterator it=readerStabs->begin(); it != readerStabs->end(); ++it) {
-                       // copy minimal or all stabs
-                       ObjectFile::Reader::Stab stab = *it;
-                       if ( !minimal || minimizeStab(stab) ) {
-                               if ( stab.type == N_SO ) {
-                                       if ( soIndex < soRanges.size() ) {
-                                               if ( (stab.string != NULL) && (strlen(stab.string) > 0) ) {
-                                                       // starting SO is associated with first atom
-                                                       stab.atom = soRanges[soIndex].first;
-                                               }
-                                               else {
-                                                       // ending SO is associated with last atom
-                                                       stab.atom = soRanges[soIndex].second;
-                                                       ++soIndex;
-                                               }
-                                       }
-                               }
-                               fStabs.push_back(stab);
-                       }
-               }
-               return;
-       }
-
-       //fprintf(stderr, "BINCL/EINCL info for %s\n", reader->getPath());
-       //for(std::vector<HeaderRange>::iterator it=ranges.begin(); it != ranges.end(); ++it) {
-       //      fprintf(stderr, "%08X %s\n", it->sum, it->begin->string);
-       //}
-
-       // see if any of these BINCL/EINCL ranges have already been seen and therefore can be replaced with EXCL
-       for(std::vector<HeaderRange>::iterator it=ranges.begin(); it != ranges.end(); ++it) {
-               if ( ! it->cannotEXCL ) {
-                       const char* header = it->begin->string;
-                       uint32_t sum = it->sum;
-                       PathToSums::iterator pos = sKnownBINCLs.find(header);
-                       if ( pos != sKnownBINCLs.end() ) {
-                               std::vector<uint32_t>& sums = pos->second;
-                               for(std::vector<uint32_t>::iterator sit=sums.begin(); sit != sums.end(); ++sit) {
-                                       if (*sit == sum) {
-                                               //fprintf(stderr, "use EXCL for %s in %s\n", header, reader->getPath());
-                                               it->useEXCL = true;
-                                               break;
-                                       }
-                               }
-                               if ( ! it->useEXCL ) {
-                                       // have seen this path, but not this checksum
-                                       //fprintf(stderr, "registering another checksum %08X for %s\n", sum, header);
-                                       sums.push_back(sum);
-                               }
-                       }
-                       else {
-                               // have not seen this path, so add to known BINCLs
-                               std::vector<uint32_t> empty;
-                               sKnownBINCLs[header] = empty;
-                               sKnownBINCLs[header].push_back(sum);
-                               //fprintf(stderr, "registering checksum %08X for %s\n", sum, header);
-                       }
-               }
-       }
-
-       // add a new set of stabs with BINCL/EINCL runs that have been seen before, replaced with EXCLs
-       curRangeIndex = -1;
-       const int maxRangeIndex = ranges.size();
-       int soIndex = 0;
-       for(std::vector<ObjectFile::Reader::Stab>::iterator it=readerStabs->begin(); it != readerStabs->end(); ++it) {
-               switch ( it->type ) {
-                       case N_BINCL:
-                               for(int i=curRangeIndex+1; i < maxRangeIndex; ++i) {
-                                       if ( ranges[i].begin == it ) {
-                                               curRangeIndex = i;
-                                               HeaderRange& range = ranges[curRangeIndex];
-                                               ObjectFile::Reader::Stab stab = *it;
-                                               stab.value = range.sum; // BINCL and EXCL have n_value set to checksum
-                                               if ( range.useEXCL )
-                                                       stab.type = N_EXCL;     // transform BINCL into EXCL
-                                               if ( !minimal )
-                                                       fStabs.push_back(stab);
-                                               break;
-                                       }
-                               }
-                               break;
-                       case N_EINCL:
-                               if ( curRangeIndex != -1 ) {
-                                       if ( !ranges[curRangeIndex].useEXCL && !minimal )
-                                               fStabs.push_back(*it);
-                                       curRangeIndex = ranges[curRangeIndex].parentRangeIndex;
-                               }
-                               break;
-                       default:
-                               if ( (curRangeIndex == -1) || !ranges[curRangeIndex].useEXCL ) {
-                                       ObjectFile::Reader::Stab stab = *it;
-                                       if ( !minimal || minimizeStab(stab) ) {
-                                               if ( stab.type == N_SO ) {
-                                                       if ( (stab.string != NULL) && (strlen(stab.string) > 0) ) {
-                                                               // starting SO is associated with first atom
-                                                               stab.atom = soRanges[soIndex].first;
-                                                       }
-                                                       else {
-                                                               // ending SO is associated with last atom
-                                                               stab.atom = soRanges[soIndex].second;
-                                                               ++soIndex;
-                                                       }
-                                               }
-                                               fStabs.push_back(stab);
-                                       }
-                               }
-               }
-       }
-
-}
-
-
-// used to prune out atoms that don't need debug notes generated
-class NoDebugNoteAtom
-{
-public:
-       NoDebugNoteAtom(const std::map<class ObjectFile::Reader*, uint32_t>& readersWithDwarfOrdinals)
-                       : fReadersWithDwarfOrdinals(readersWithDwarfOrdinals) {}
-
-       bool operator()(const ObjectFile::Atom* atom) const {
-               if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn )
-                       return true;
-               if ( atom->getName() == NULL )
-                       return true;
-               if ( fReadersWithDwarfOrdinals.find(atom->getFile()) == fReadersWithDwarfOrdinals.end() )
-                       return true;
-               return false;
-       }
-
-private:
-       const std::map<class ObjectFile::Reader*, uint32_t>& fReadersWithDwarfOrdinals;
-};
-
-// used to sort atoms with debug notes
-class ReadersWithDwarfSorter
-{
-public:
-       ReadersWithDwarfSorter(const std::map<class ObjectFile::Reader*, uint32_t>& readersWithDwarfOrdinals,
-                                                  const std::map<const class ObjectFile::Atom*, uint32_t>& atomOrdinals)
-                       : fReadersWithDwarfOrdinals(readersWithDwarfOrdinals), fAtomOrdinals(atomOrdinals) {}
-
-       bool operator()(const ObjectFile::Atom* left, const ObjectFile::Atom* right) const
-       {
-               // first sort by reader
-               unsigned int leftReaderIndex  = fReadersWithDwarfOrdinals.find(left->getFile())->second;
-               unsigned int rightReaderIndex = fReadersWithDwarfOrdinals.find(right->getFile())->second;
-               if ( leftReaderIndex != rightReaderIndex )
-                       return (leftReaderIndex < rightReaderIndex);
-
-               // then sort by atom ordinal
-               unsigned int leftAtomIndex  = fAtomOrdinals.find(left)->second;
-               unsigned int rightAtomIndex = fAtomOrdinals.find(right)->second;
-               return leftAtomIndex < rightAtomIndex;
-       }
-
-private:
-       const std::map<class ObjectFile::Reader*, uint32_t>& fReadersWithDwarfOrdinals;
-       const std::map<const class ObjectFile::Atom*, uint32_t>& fAtomOrdinals;
-};
-
-
-
-
-
-void Linker::synthesizeDebugNotes(std::vector<class ObjectFile::Atom*>& allAtomsByReader)
-{
-       // synthesize "debug notes" and add them to master stabs vector
-       const char* dirPath = NULL;
-       const char* filename = NULL;
-       bool wroteStartSO = false;
-       bool useZeroOSOModTime = (getenv("RC_RELEASE") != NULL);
-       __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals>  seenFiles;
-       for (std::vector<ObjectFile::Atom*>::iterator it=allAtomsByReader.begin(); it != allAtomsByReader.end(); it++) {
-               ObjectFile::Atom* atom = *it;
-               const char* newDirPath;
-               const char* newFilename;
-               //fprintf(stderr, "debug note for %s\n", atom->getDisplayName());
-               if ( atom->getTranslationUnitSource(&newDirPath, &newFilename) ) {
-                       // 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] != '/') )
-                                       asprintf((char**)&newDirPath, "%s/", newDirPath);
-                               if ( filename != NULL ) {
-                                       // translation unit change, emit ending SO
-                                       ObjectFile::Reader::Stab endFileStab;
-                                       endFileStab.atom                = NULL;
-                                       endFileStab.type                = N_SO;
-                                       endFileStab.other               = 1;
-                                       endFileStab.desc                = 0;
-                                       endFileStab.value               = 0;
-                                       endFileStab.string              = "";
-                                       fStabs.push_back(endFileStab);
-                               }
-                               // new translation unit, emit start SO's
-                               ObjectFile::Reader::Stab dirPathStab;
-                               dirPathStab.atom                = NULL;
-                               dirPathStab.type                = N_SO;
-                               dirPathStab.other               = 0;
-                               dirPathStab.desc                = 0;
-                               dirPathStab.value               = 0;
-                               dirPathStab.string              = newDirPath;
-                               fStabs.push_back(dirPathStab);
-                               ObjectFile::Reader::Stab fileStab;
-                               fileStab.atom           = NULL;
-                               fileStab.type           = N_SO;
-                               fileStab.other          = 0;
-                               fileStab.desc           = 0;
-                               fileStab.value          = 0;
-                               fileStab.string         = newFilename;
-                               fStabs.push_back(fileStab);
-                               // Synthesize OSO for start of file
-                               ObjectFile::Reader::Stab objStab;
-                               objStab.atom            = NULL;
-                               objStab.type            = N_OSO;
-                               // <rdar://problem/6337329> linker should put cpusubtype in n_sect field of nlist entry for N_OSO debug note entries
-                               objStab.other           = atom->getFile()->updateCpuConstraint(0); 
-                               objStab.desc            = 1;
-                               objStab.value           = useZeroOSOModTime ? 0 : atom->getFile()->getModificationTime();
-                               objStab.string          = assureFullPath(atom->getFile()->getPath());
-                               fStabs.push_back(objStab);
-                               wroteStartSO = true;
-                               // add the source file path to seenFiles so it does not show up in SOLs
-                               seenFiles.insert(newFilename);
-                       }
-                       filename = newFilename;
-                       dirPath = newDirPath;
-                       if ( atom->getSegment().isContentExecutable() && (strncmp(atom->getSectionName(), "__text", 6) == 0) ) {
-                               // Synthesize BNSYM and start FUN stabs
-                               ObjectFile::Reader::Stab beginSym;
-                               beginSym.atom           = atom;
-                               beginSym.type           = N_BNSYM;
-                               beginSym.other          = 1;
-                               beginSym.desc           = 0;
-                               beginSym.value          = 0;
-                               beginSym.string         = "";
-                               fStabs.push_back(beginSym);
-                               ObjectFile::Reader::Stab startFun;
-                               startFun.atom           = atom;
-                               startFun.type           = N_FUN;
-                               startFun.other          = 1;
-                               startFun.desc           = 0;
-                               startFun.value          = 0;
-                               startFun.string         = atom->getName();
-                               fStabs.push_back(startFun);
-                               // Synthesize any SOL stabs needed
-                               std::vector<ObjectFile::LineInfo>* lineInfo = atom->getLineInfo();
-                               if ( lineInfo != NULL ) {
-                                       const char* curFile = NULL;
-                                       for (std::vector<ObjectFile::LineInfo>::iterator it = lineInfo->begin(); it != lineInfo->end(); ++it) {
-                                               if ( it->fileName != curFile ) {
-                                                       if ( seenFiles.count(it->fileName) == 0 ) {
-                                                               seenFiles.insert(it->fileName);
-                                                               ObjectFile::Reader::Stab sol;
-                                                               sol.atom                = 0;
-                                                               sol.type                = N_SOL;
-                                                               sol.other               = 0;
-                                                               sol.desc                = 0;
-                                                               sol.value               = 0;
-                                                               sol.string              = it->fileName;
-                                                               fStabs.push_back(sol);
-                                                       }
-                                                       curFile = it->fileName;
-                                               }
-                                       }
-                               }
-                               // Synthesize end FUN and ENSYM stabs
-                               ObjectFile::Reader::Stab endFun;
-                               endFun.atom                     = atom;
-                               endFun.type                     = N_FUN;
-                               endFun.other            = 0;
-                               endFun.desc                     = 0;
-                               endFun.value            = 0;
-                               endFun.string           = "";
-                               fStabs.push_back(endFun);
-                               ObjectFile::Reader::Stab endSym;
-                               endSym.atom                     = atom;
-                               endSym.type                     = N_ENSYM;
-                               endSym.other            = 1;
-                               endSym.desc                     = 0;
-                               endSym.value            = 0;
-                               endSym.string           = "";
-                               fStabs.push_back(endSym);
-                       }
-                       else if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn ) {
-                               // no stabs for atoms that would not be in the symbol table
-                       }
-                       else if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAsAbsolute ) {
-                               // no stabs for absolute symbols
-                       }
-                       else if ( (strcmp(atom->getSectionName(), "__eh_frame") == 0) ) {
-                               // no stabs for .eh atoms
-                       }
-                       else if ( (strncmp(atom->getName(), "__dtrace_probe$", 15) == 0) ) {
-                               // no stabs for old style dtrace probes
-                       }
-                       else {
-                               ObjectFile::Reader::Stab globalsStab;
-                               const char* name = atom->getName();
-                               if ( atom->getScope() == ObjectFile::Atom::scopeTranslationUnit ) {
-                                       // Synthesize STSYM stab for statics
-                                       globalsStab.atom                = atom;
-                                       globalsStab.type                = N_STSYM;
-                                       globalsStab.other               = 1;
-                                       globalsStab.desc                = 0;
-                                       globalsStab.value               = 0;
-                                       globalsStab.string              = name;
-                                       fStabs.push_back(globalsStab);
-                               }
-                               else {
-                                       // Synthesize GSYM stab for other globals
-                                       globalsStab.atom                = atom;
-                                       globalsStab.type                = N_GSYM;
-                                       globalsStab.other               = 1;
-                                       globalsStab.desc                = 0;
-                                       globalsStab.value               = 0;
-                                       globalsStab.string              = name;
-                                       fStabs.push_back(globalsStab);
-                               }
-                       }
-               }
-       }
-
-       if ( wroteStartSO ) {
-               //  emit ending SO
-               ObjectFile::Reader::Stab endFileStab;
-               endFileStab.atom                = NULL;
-               endFileStab.type                = N_SO;
-               endFileStab.other               = 1;
-               endFileStab.desc                = 0;
-               endFileStab.value               = 0;
-               endFileStab.string              = "";
-               fStabs.push_back(endFileStab);
-       }
-}
-
-
-
-
-void Linker::collectDebugInfo()
-{
-       std::map<const class ObjectFile::Atom*, uint32_t>       atomOrdinals;
-       fStartDebugTime = mach_absolute_time();
-       if ( fOptions.readerOptions().fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone ) {
-
-               // determine mixture of stabs and dwarf
-               bool someStabs = false;
-               bool someDwarf = false;
-               for (std::vector<class ObjectFile::Reader*>::iterator it=fReadersThatHaveSuppliedAtoms.begin();
-                               it != fReadersThatHaveSuppliedAtoms.end();
-                               it++) {
-                       ObjectFile::Reader* reader = *it;
-                       if ( reader != NULL ) {
-                               switch ( reader->getDebugInfoKind() ) {
-                                       case ObjectFile::Reader::kDebugInfoNone:
-                                               break;
-                                       case ObjectFile::Reader::kDebugInfoStabs:
-                                               someStabs = true;
-                                               break;
-                                       case ObjectFile::Reader::kDebugInfoDwarf:
-                                               someDwarf = true;
-                                               fCreateUUID = true;
-                                               break;
-                                   case ObjectFile::Reader::kDebugInfoStabsUUID:
-                                               someStabs = true;
-                                               fCreateUUID = true;
-                                               break;
-                                       default:
-                                               throw "Unhandled type of debug information";
-                               }
-                       }
-               }
-
-               if ( someDwarf || someStabs ) {
-                       // try to minimize re-allocations
-                       fStabs.reserve(1024);
-
-                       // make mapping from atoms to ordinal
-                       uint32_t ordinal = 1;
-                       for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
-                               atomOrdinals[*it] = ordinal++;
-                       }
-               }
-
-               // process all dwarf .o files as a batch
-               if ( someDwarf ) {
-                       // make mapping from readers with dwarf to ordinal
-                       std::map<class ObjectFile::Reader*, uint32_t>   readersWithDwarfOrdinals;
-                       uint32_t readerOrdinal = 1;
-                       for (std::vector<class ObjectFile::Reader*>::iterator it=fReadersThatHaveSuppliedAtoms.begin();
-                                       it != fReadersThatHaveSuppliedAtoms.end();
-                                       it++) {
-                               ObjectFile::Reader* reader = *it;
-                               if ( (reader != NULL) && (reader->getDebugInfoKind() == ObjectFile::Reader::kDebugInfoDwarf) ) {
-                                       readersWithDwarfOrdinals[reader] = readerOrdinal++;
-                               }
-                       }
-
-                       // make a vector of atoms
-                       std::vector<class ObjectFile::Atom*> allAtomsByReader(fAllAtoms.begin(), fAllAtoms.end());
-                       // remove those not from a reader that has dwarf
-                       allAtomsByReader.erase(std::remove_if(allAtomsByReader.begin(), allAtomsByReader.end(),
-                                                               NoDebugNoteAtom(readersWithDwarfOrdinals)), allAtomsByReader.end());
-                       // sort by reader then atom ordinal
-                       std::sort(allAtomsByReader.begin(), allAtomsByReader.end(), ReadersWithDwarfSorter(readersWithDwarfOrdinals, atomOrdinals));
-                       // add debug notes for each atom
-                       this->synthesizeDebugNotes(allAtomsByReader);
-               }
-
-               // process all stabs .o files one by one
-               if ( someStabs ) {
-                       // get stabs from each reader, in command line order
-                       for (std::vector<class ObjectFile::Reader*>::iterator it=fReadersThatHaveSuppliedAtoms.begin();
-                                       it != fReadersThatHaveSuppliedAtoms.end();
-                                       it++) {
-                               ObjectFile::Reader* reader = *it;
-                               if ( reader != NULL ) {
-                                       switch ( reader->getDebugInfoKind() ) {
-                                               case ObjectFile::Reader::kDebugInfoDwarf:
-                                               case ObjectFile::Reader::kDebugInfoNone:
-                                                       // do nothing
-                                                       break;
-                                               case ObjectFile::Reader::kDebugInfoStabs:
-                                               case ObjectFile::Reader::kDebugInfoStabsUUID:
-                                                       collectStabs(reader, atomOrdinals);
-                                                       break;
-                                               default:
-                                                       throw "Unhandled type of debug information";
-                                       }
-                               }
-                       }
-                       // remove stabs associated with atoms that won't be in output
-                       std::set<class ObjectFile::Atom*>       allAtomsSet;
-                       allAtomsSet.insert(fAllAtoms.begin(), fAllAtoms.end());
-                       fStabs.erase(std::remove_if(fStabs.begin(), fStabs.end(), NotInSet(allAtomsSet)), fStabs.end());
-               }
-       }
-}
-
-void Linker::writeOutput()
-{
-       // <rdar://problem/6933931> ld -r of empty .o file should preserve sub-type
-       // <rdar://problem/7049478> empty dylib should have subtype from command line
-       if ( fOptions.preferSubArchitecture() && (fOptions.architecture() == CPU_TYPE_ARM) ) {
-               fCurrentCpuConstraint = (ObjectFile::Reader::CpuConstraint)fOptions.subArchitecture();
-       }
-
-       if ( fOptions.forceCpuSubtypeAll() )
-               fCurrentCpuConstraint = ObjectFile::Reader::kCpuAny;
-
-       fStartWriteTime = mach_absolute_time();
-       // tell writer about each segment's atoms
-       fOutputFileSize = fOutputFile->write(fAllAtoms, fStabs, this->entryPoint(true), 
-                                                                                       fCreateUUID, fCanScatter, 
-                                                                                       fCurrentCpuConstraint,
-                                                                                       fRegularDefAtomsThatOverrideADylibsWeakDef,  
-                                                                                       fGlobalSymbolTable.hasExternalWeakDefinitions());
-}
-
-const char* Linker::fileArch(const void* p)
-{
-       const uint8_t* bytes = (uint8_t*)p;
-       const char* result;
-       result = mach_o::relocatable::Reader<ppc>::fileKind(bytes);
-       if ( result != NULL  )
-                return result;
-       result = mach_o::relocatable::Reader<ppc64>::fileKind(bytes);
-       if ( result != NULL  )
-                return result;
-       result = mach_o::relocatable::Reader<x86>::fileKind(bytes);
-       if ( result != NULL  )
-                return result;
-       result = mach_o::relocatable::Reader<x86_64>::fileKind(bytes);
-       if ( result != NULL  )
-                return result;
-       result = mach_o::relocatable::Reader<arm>::fileKind(bytes);
-       if ( result != NULL  )
-                return result;
-                
-       result = lto::Reader::fileKind(bytes);
-       if ( result != NULL  )
-                return result;
-       
-       return "unsupported file format";        
-}
-
-ObjectFile::Reader* Linker::createReader(const Options::FileInfo& info)
-{
-       // map in whole file
-       uint64_t len = info.fileLen;
-       int fd = ::open(info.path, O_RDONLY, 0);
-       if ( fd == -1 )
-               throwf("can't open file, errno=%d", errno);
-       if ( info.fileLen < 20 )
-               throw "file too small";
-
-       uint8_t* p = (uint8_t*)::mmap(NULL, info.fileLen, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
-       if ( p == (uint8_t*)(-1) )
-               throwf("can't map file, errno=%d", errno);
-
-       // if fat file, skip to architecture we want
-       // Note: fat header is always big-endian
-       bool isFatFile = false;
-       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;
-               if ( fOptions.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) {
-                               if ( (OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)fArchitecture)
-                                 && (OSSwapBigToHostInt32(archs[i].cpusubtype) == (uint32_t)fOptions.subArchitecture()) ) {
-                                       sliceToUse = i;
-                                       sliceFound = true;
-                                       break;
-                               }
-                       }
-               }
-               if ( !sliceFound ) {
-                       // look for any slice that matches just cpu-type
-                       for (uint32_t i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
-                               if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)fArchitecture ) {
-                                       sliceToUse = i;
-                                       sliceFound = true;
-                                       break;
-                               }
-                       }
-               }
-               if ( sliceFound ) {
-                       uint32_t fileOffset = OSSwapBigToHostInt32(archs[sliceToUse].offset);
-                       len = OSSwapBigToHostInt32(archs[sliceToUse].size);
-                       // if requested architecture is page aligned within fat file, then remap just that portion of file
-                       if ( (fileOffset & 0x00000FFF) == 0 ) {
-                               // unmap whole file
-                               munmap((caddr_t)p, info.fileLen);
-                               // re-map just part we need
-                               p = (uint8_t*)::mmap(NULL, len, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, fileOffset);
-                               if ( p == (uint8_t*)(-1) )
-                                       throwf("can't re-map file, errno=%d", errno);
-                       }
-                       else {
-                               p = &p[fileOffset];
-                       }
-               }
-       }
-       ::close(fd);
-
-       bool objSubtypeMustMatch = (fOptions.preferSubArchitecture() && !fOptions.allowSubArchitectureMismatches());
-       switch (fArchitecture) {
-               case CPU_TYPE_POWERPC:
-                       if ( mach_o::relocatable::Reader<ppc>::validFile(p) )
-                               return this->addObject(new mach_o::relocatable::Reader<ppc>::Reader(p, info.path, info.modTime, fOptions.readerOptions(), fNextInputOrdinal), info, len);
-                       else if ( mach_o::dylib::Reader<ppc>::validFile(p, info.options.fBundleLoader) )
-                               return this->addDylib(new mach_o::dylib::Reader<ppc>::Reader(p, len, info.path, info.options, fOptions.readerOptions(), fNextInputOrdinal), info, len);
-                       else if ( archive::Reader<ppc>::validFile(p, len) )
-                               return this->addArchive(new archive::Reader<ppc>::Reader(p, len, info.path, info.modTime, info.options, fOptions.readerOptions(), fNextInputOrdinal), info, len);
-                       break;
-               case CPU_TYPE_POWERPC64:
-                       if ( mach_o::relocatable::Reader<ppc64>::validFile(p) )
-                               return this->addObject(new mach_o::relocatable::Reader<ppc64>::Reader(p, info.path, info.modTime, fOptions.readerOptions(), fNextInputOrdinal), info, len);
-                       else if ( mach_o::dylib::Reader<ppc64>::validFile(p, info.options.fBundleLoader) )
-                               return this->addDylib(new mach_o::dylib::Reader<ppc64>::Reader(p, len, info.path, info.options, fOptions.readerOptions(), fNextInputOrdinal), info, len);
-                       else if ( archive::Reader<ppc64>::validFile(p, len) )
-                               return this->addArchive(new archive::Reader<ppc64>::Reader(p, len, info.path, info.modTime, info.options, fOptions.readerOptions(), fNextInputOrdinal), info, len);
-                       break;
-               case CPU_TYPE_I386:
-                       if ( mach_o::relocatable::Reader<x86>::validFile(p) )
-                               return this->addObject(new mach_o::relocatable::Reader<x86>::Reader(p, info.path, info.modTime, fOptions.readerOptions(), fNextInputOrdinal), info, len);
-                       else if ( mach_o::dylib::Reader<x86>::validFile(p, info.options.fBundleLoader) )
-                               return this->addDylib(new mach_o::dylib::Reader<x86>::Reader(p, len, info.path, info.options, fOptions.readerOptions(), fNextInputOrdinal), info, len);
-                       else if ( archive::Reader<x86>::validFile(p, len) )
-                               return this->addArchive(new archive::Reader<x86>::Reader(p, len, info.path, info.modTime, info.options, fOptions.readerOptions(), fNextInputOrdinal), info, len);
-                       break;
-               case CPU_TYPE_X86_64:
-                       if ( mach_o::relocatable::Reader<x86_64>::validFile(p) )
-                               return this->addObject(new mach_o::relocatable::Reader<x86_64>::Reader(p, info.path, info.modTime, fOptions.readerOptions(), fNextInputOrdinal), info, len);
-                       else if ( mach_o::dylib::Reader<x86_64>::validFile(p, info.options.fBundleLoader) )
-                               return this->addDylib(new mach_o::dylib::Reader<x86_64>::Reader(p, len, info.path, info.options, fOptions.readerOptions(), fNextInputOrdinal), info, len);
-                       else if ( archive::Reader<x86_64>::validFile(p, len) )
-                               return this->addArchive(new archive::Reader<x86_64>::Reader(p, len, info.path, info.modTime, info.options, fOptions.readerOptions(), fNextInputOrdinal), info, len);
-               case CPU_TYPE_ARM:
-                       if ( mach_o::relocatable::Reader<arm>::validFile(p, objSubtypeMustMatch, fOptions.subArchitecture()) )
-                                       return this->addObject(new mach_o::relocatable::Reader<arm>::Reader(p, info.path, info.modTime, fOptions.readerOptions(), fNextInputOrdinal), info, len);
-                       else if ( mach_o::dylib::Reader<arm>::validFile(p, info.options.fBundleLoader) )
-                               return this->addDylib(new mach_o::dylib::Reader<arm>::Reader(p, len, info.path, info.options, fOptions.readerOptions(), fNextInputOrdinal), info, len);
-                       else if ( archive::Reader<arm>::validFile(p, len) )
-                               return this->addArchive(new archive::Reader<arm>::Reader(p, len, info.path, info.modTime, info.options, fOptions.readerOptions(), fNextInputOrdinal), info, len);
-                       break;
-       }
-
-#if LTO_SUPPORT
-       if ( lto::Reader::validFile(p, len, fArchitecture) ) {
-               return this->addObject(new lto::Reader(p, len, info.path, info.modTime, fOptions.readerOptions(), fArchitecture), info, len);
-       }
-       else if ( lto::Reader::fileKind((uint8_t*)p) != NULL ) {
-               if ( lto::Reader::loaded() ) {
-                       throwf("file was built for %s which is not the architecture being linked (%s)", fileArch(p), fArchitectureName);
-               }
-               else {
-                       const char* libLTO = "libLTO.dylib";
-                       char ldPath[PATH_MAX];
-                       char tmpPath[PATH_MAX];
-                       char libLTOPath[PATH_MAX];
-                       uint32_t bufSize = PATH_MAX;
-                       if ( _NSGetExecutablePath(ldPath, &bufSize) != -1 ) {
-                               if ( realpath(ldPath, tmpPath) != NULL ) {
-                                       char* lastSlash = strrchr(tmpPath, '/');
-                                       if ( lastSlash != NULL )
-                                               strcpy(lastSlash, "/../lib/libLTO.dylib");
-                                       libLTO = tmpPath;
-                                       if ( realpath(tmpPath, libLTOPath) != NULL ) 
-                                               libLTO = libLTOPath;
-                               }
-                       }
-                       throwf("could not process llvm bitcode object file, because %s could not be loaded", libLTO);
-               }
-       }
-#endif
-       // error handling
-       if ( ((fat_header*)p)->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
-               throwf("missing required architecture %s in file", fArchitectureName);
-       }
-       else {
-               if ( isFatFile )
-                       throwf("file is universal but does not contain a(n) %s slice", fArchitectureName);
-               else
-                       throwf("file was built for %s which is not the architecture being linked (%s)", fileArch(p), fArchitectureName);
-       }
-}
-
-void Linker::logDylib(ObjectFile::Reader* reader, bool indirect)
-{
-       if ( fOptions.readerOptions().fTraceDylibs ) {
-               const char* fullPath = reader->getPath();
-               char realName[MAXPATHLEN];
-               if ( realpath(fullPath, realName) != NULL )
-                       fullPath = realName;
-               if ( indirect )
-                       logTraceInfo("[Logging for XBS] Used indirect dynamic library: %s\n", fullPath);
-               else
-                       logTraceInfo("[Logging for XBS] Used dynamic library: %s\n", fullPath);
-       }
-}
-
-
-
-ObjectFile::Reader* Linker::findDylib(const char* installPath, const char* fromPath)
-{
-       //fprintf(stderr, "findDylib(%s, %s)\n", installPath, fromPath);
-       InstallNameToReader::iterator pos = fDylibMap.find(installPath);
-       if ( pos != fDylibMap.end() ) {
-               return pos->second;
-       }
-       else {
-               // allow -dylib_path option to override indirect library to use
-               for (std::vector<Options::DylibOverride>::iterator dit = fOptions.dylibOverrides().begin(); dit != fOptions.dylibOverrides().end(); ++dit) {
-                       if ( strcmp(dit->installName,installPath) == 0 ) {\
-                               try {
-                                       Options::FileInfo info = fOptions.findFile(dit->useInstead);
-                                       ObjectFile::Reader* reader = this->createReader(info);
-                                       fDylibMap[strdup(installPath)] = reader;
-                                       this->logDylib(reader, true);
-                                       return reader;
-                               }
-                               catch (const char* msg) {
-                                       warning("ignoring -dylib_file option, %s", msg);
-                               }
-                       }
-               }
-               char newPath[MAXPATHLEN];
-               // handle @loader_path
-               if ( strncmp(installPath, "@loader_path/", 13) == 0 ) {
-                       strcpy(newPath, fromPath);
-                       char* addPoint = strrchr(newPath,'/');
-                       if ( addPoint != NULL )
-                               strcpy(&addPoint[1], &installPath[13]);
-                       else
-                               strcpy(newPath, &installPath[13]);
-                       installPath = newPath;
-               }
-               // note: @executable_path case is handled inside findFileUsingPaths()
-               // search for dylib using -F and -L paths
-               Options::FileInfo info = fOptions.findFileUsingPaths(installPath);
-               try {
-                       ObjectFile::Reader* reader = this->createReader(info);
-                       fDylibMap[strdup(installPath)] = reader;
-                       this->logDylib(reader, true);
-                       return reader;
-               }
-               catch (const char* msg) {
-                       throwf("in %s, %s", info.path, msg);
-               }
-       }
-}
-
-
-void Linker::processDylibs()
-{
-       fAllDirectDylibsLoaded = true;
-
-       // mark all dylibs initially specified as required and check if they can be used
-       for (InstallNameToReader::iterator it=fDylibMap.begin(); it != fDylibMap.end(); it++) {
-               it->second->setExplicitlyLinked();
-               this->checkDylibClientRestrictions(it->second);
-       }
-       
-       // keep processing dylibs until no more dylibs are added
-       unsigned long lastMapSize = 0;
-       while ( lastMapSize != fDylibMap.size() ) {
-               lastMapSize = fDylibMap.size();
-               // can't iterator fDylibMap while modifying it, so use temp buffer
-               std::vector<ObjectFile::Reader*> currentUnprocessedReaders;
-               for (InstallNameToReader::iterator it=fDylibMap.begin(); it != fDylibMap.end(); it++) {
-                       if ( fDylibsProcessed.count(it->second) == 0 )
-                               currentUnprocessedReaders.push_back(it->second);
-               }
-               for (std::vector<ObjectFile::Reader*>::iterator it=currentUnprocessedReaders.begin(); it != currentUnprocessedReaders.end(); it++) {
-                       fDylibsProcessed.insert(*it);
-                       (*it)->processIndirectLibraries(this);
-               }
-       }
-       
-       // go back over original dylibs and mark sub frameworks as re-exported
-       if ( fOptions.outputKind() == Options::kDynamicLibrary ) {
-               const char* myLeaf = strrchr(fOptions.installPath(), '/');
-               if ( myLeaf != NULL ) {
-                       for (std::vector<class ObjectFile::Reader*>::iterator it=fInputFiles.begin(); it != fInputFiles.end(); it++) {
-                               ObjectFile::Reader* reader = *it;
-                               const char* childParent = reader->parentUmbrella();
-                               if ( childParent != NULL ) {
-                                       if ( strcmp(childParent, &myLeaf[1]) == 0 ) {
-                                               // set re-export bit of info
-                                               std::map<ObjectFile::Reader*,LibraryOptions>::iterator pos = fDylibOptionsMap.find(reader);
-                                               if ( pos != fDylibOptionsMap.end() ) {
-                                                       pos->second.fReExport = true;
-                                               }
-                                       }
-                               }
-                       }
-               }
-       }
-       
-}
-
-       
-
-void Linker::createReaders()
-{
-       fStartCreateReadersTime = mach_absolute_time();
-       std::vector<Options::FileInfo>& files = fOptions.getInputFiles();
-       const int count = files.size();
-       if ( count == 0 )
-               throw "no object files specified";
-       // add all direct object, archives, and dylibs
-       for (int i=0; i < count; ++i) {
-               Options::FileInfo& entry = files[i];
-               // ignore /usr/lib/dyld on command line in crt.o build
-               if ( strcmp(entry.path, "/usr/lib/dyld") != 0 ) {
-                       try {
-                               this->addInputFile(this->createReader(entry), entry);
-                       }
-                       catch (const char* msg) {
-                               if ( (strstr(msg, "architecture") != NULL) && !fOptions.errorOnOtherArchFiles() ) {
-                                       if ( fOptions.ignoreOtherArchInputFiles() ) {
-                                               // ignore, because this is about an architecture not in use
-                                       }
-                                       else {
-                                               warning("in %s, %s", entry.path, msg);
-                                       }
-                               }
-                               else {
-                                       throwf("in %s, %s", entry.path, msg);
-                               }
-                       }
-               }
-       }
-
-       this->processDylibs();
-}
-
-
-
-ObjectFile::Reader* Linker::addArchive(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen)
-{
-       fNextInputOrdinal += mappedLen;
-       // remember which readers are archives because they are logged differently
-       fArchiveReaders.insert(reader);
-
-       // update stats
-       fTotalArchiveSize += mappedLen;
-       ++fTotalArchivesLoaded;
-       return reader;
-}
-
-ObjectFile::Reader* Linker::addObject(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen)
-{
-       fNextInputOrdinal += mappedLen;
-       // any .o files that don't have MH_SUBSECTIONS_VIA_SYMBOLS, that means a generated .o file can't
-       if ( (fOptions.outputKind() == Options::kObjectFile) && !reader->canScatterAtoms() )
-               fCanScatter = false;
-
-       // update stats
-       fTotalObjectSize += mappedLen;
-       ++fTotalObjectLoaded;
-       return reader;
-}
-
-
-void Linker::checkDylibClientRestrictions(ObjectFile::Reader* reader)
-{
-       // Check for any restrictions on who can link with this dylib  
-       const char* readerParentName = reader->parentUmbrella() ;
-       std::vector<const char*>* clients = reader->getAllowableClients();
-       if ( (readerParentName != NULL) || (clients != NULL) ) {
-               // only dylibs that are in an umbrella or have a client list need verification
-               const char* installName = fOptions.installPath();
-               const char* installNameLastSlash = strrchr(installName, '/');
-               bool isParent = false;
-               bool isSibling = false;
-               bool isAllowableClient = false;
-               // There are three cases:
-               if ( (readerParentName != NULL) && (installNameLastSlash != NULL) ) {
-                       // case 1) The dylib has a parent umbrella, and we are creating the parent umbrella
-                       isParent = ( strcmp(&installNameLastSlash[1], readerParentName) == 0 );
-                       
-                       // hack to support umbrella variants that encode the variant name in the install name 
-                       // e.g. CoreServices_profile
-                       if ( !isParent ) {
-                               const char* underscore = strchr(&installNameLastSlash[1], '_');
-                               if ( underscore != NULL ) {
-                                       isParent = ( strncmp(&installNameLastSlash[1], readerParentName, underscore-installNameLastSlash-1) == 0 );
-                               }
-                       }
-                       
-                       // case 2) The dylib has a parent umbrella, and we are creating a sibling with the same parent
-                       isSibling = ( (fOptions.umbrellaName() != NULL) && (strcmp(fOptions.umbrellaName(), readerParentName) == 0) );
-               }
-
-               if ( !isParent && !isSibling && (clients != NULL) ) {
-                       // case 3) the dylib has a list of allowable clients, and we are creating one of them
-                       const char* clientName = fOptions.clientName();
-                       int clientNameLen = 0;
-                       if ( clientName != NULL ) {
-                               // use client name as specified on command line
-                               clientNameLen = strlen(clientName);
-                       }
-                       else {
-                               // infer client name from output path (e.g. xxx/libfoo_variant.A.dylib --> foo, Bar.framework/Bar_variant --> Bar)
-                               clientName = installName;
-                               clientNameLen = strlen(clientName);
-                               // starts after last slash
-                               if ( installNameLastSlash != NULL )
-                                       clientName = &installNameLastSlash[1];
-                               if ( strncmp(clientName, "lib", 3) == 0 )
-                                       clientName = &clientName[3];
-                               // up to first dot
-                               const char* firstDot = strchr(clientName, '.');
-                               if ( firstDot != NULL )
-                                       clientNameLen = firstDot - clientName;
-                               // up to first underscore
-                               const char* firstUnderscore = strchr(clientName, '_');
-                               if ( (firstUnderscore != NULL) && ((firstUnderscore - clientName) < clientNameLen) )
-                                       clientNameLen = firstUnderscore - clientName;
-                       }
-
-                       // Use clientName to check if this dylib is able to link against the allowable clients.
-                       for (std::vector<const char*>::iterator it = clients->begin(); it != clients->end(); it++) {
-                               if ( strncmp(*it, clientName, clientNameLen) == 0 )
-                                       isAllowableClient = true;
-                       }
-               }
-       
-               if ( !isParent && !isSibling && !isAllowableClient ) {
-                       if ( readerParentName != NULL ) {
-                               throwf("cannot link directly with %s.  Link against the umbrella framework '%s.framework' instead.", 
-                                       reader->getPath(), readerParentName);
-                       }
-                       else {
-                               throwf("cannot link directly with %s", reader->getPath());
-                       }
-               }
-       }
-}
-
-
-ObjectFile::Reader* Linker::addDylib(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen)
-{
-       switch ( fOptions.outputKind() ) {
-               case Options::kDynamicExecutable:
-               case Options::kDynamicLibrary:
-               case Options::kDynamicBundle:
-                       break;
-               case Options::kStaticExecutable:
-               case Options::kDyld:
-               case Options::kPreload:
-               case Options::kObjectFile:
-               case Options::kKextBundle:
-                       warning("unexpected dylib (%s) on link line", reader->getPath());
-                       break;
-       }
-
-       fNextInputOrdinal += mappedLen;
-       if ( (reader->getInstallPath() == NULL) && !info.options.fBundleLoader ) {
-               // this is a "blank" stub
-               // silently ignore it
-               return reader;
-       }
-       // add to map of loaded dylibs
-       const char* installPath = reader->getInstallPath();
-       if ( installPath != NULL ) {
-               InstallNameToReader::iterator pos = fDylibMap.find(installPath);
-               if ( pos == fDylibMap.end() ) {
-                       fDylibMap[strdup(installPath)] = reader;
-               }
-               else {
-                       InstallNameToReader::iterator pos2 = fDylibMap.find(reader->getPath());
-                       if ( pos2 == fDylibMap.end() ) 
-                               fDylibMap[strdup(reader->getPath())] = reader;
-                       else
-                               warning("duplicate dylib %s", reader->getPath());
-               }
-       }
-       else if ( info.options.fBundleLoader )
-               fBundleLoaderReader = reader;
-
-       // log direct readers
-       if ( !fAllDirectDylibsLoaded ) 
-               this->logDylib(reader, false);
-
-       // update stats
-       ++fTotalDylibsLoaded;
-
-       return reader;
-}
-
-
-void Linker::logTraceInfo (const char* format, ...)
-{
-       static int trace_file = -1;
-       char trace_buffer[MAXPATHLEN * 2];
-       char *buffer_ptr;
-       int length;
-       ssize_t amount_written;
-       const char *trace_file_path = fOptions.readerOptions().fTraceOutputFile;
-
-       if(trace_file == -1) {
-               if(trace_file_path != NULL) {
-                       trace_file = open(trace_file_path, O_WRONLY | O_APPEND | O_CREAT, 0666);
-                       if(trace_file == -1)
-                               throwf("Could not open or create trace file: %s", trace_file_path);
-               }
-               else {
-                       trace_file = fileno(stderr);
-               }
-       }
-
-    va_list ap;
-       va_start(ap, format);
-       length = vsnprintf(trace_buffer, sizeof(trace_buffer), format, ap);
-       va_end(ap);
-       buffer_ptr = trace_buffer;
-
-       while(length > 0) {
-               amount_written = write(trace_file, buffer_ptr, length);
-               if(amount_written == -1)
-                       /* Failure to write shouldn't fail the build. */
-                       return;
-               buffer_ptr += amount_written;
-               length -= amount_written;
-       }
-}
-
-
-
-void Linker::createWriter()
-{
-       fStartCreateWriterTime = mach_absolute_time();
-
-       // make a vector out of all required dylibs in fDylibMap
-       std::vector<ExecutableFile::DyLibUsed>  dynamicLibraries;
-       // need to preserve command line order 
-       for (std::vector<class ObjectFile::Reader*>::iterator it=fInputFiles.begin(); it != fInputFiles.end(); it++) {
-               ObjectFile::Reader* reader = *it;
-               for (InstallNameToReader::iterator mit=fDylibMap.begin(); mit != fDylibMap.end(); mit++) {
-                       if ( reader == mit->second ) {
-                               ExecutableFile::DyLibUsed dylibInfo;
-                               dylibInfo.reader = reader;
-                               dylibInfo.options = fDylibOptionsMap[reader];
-                               dynamicLibraries.push_back(dylibInfo);
-                               break;
-                       }
-               }
-       }
-       // then add any other dylibs
-       for (InstallNameToReader::iterator it=fDylibMap.begin(); it != fDylibMap.end(); it++) {
-               if ( it->second->implicitlyLinked()  ) {
-                       // if not already in dynamicLibraries
-                       bool alreadyInDynamicLibraries = false;
-                       for (std::vector<ExecutableFile::DyLibUsed>::iterator dit=dynamicLibraries.begin(); dit != dynamicLibraries.end(); dit++) {
-                               if ( dit->reader == it->second ) {
-                                       alreadyInDynamicLibraries = true;
-                                       break;
-                               }
-                       }
-                       if ( ! alreadyInDynamicLibraries ) {    
-                               ExecutableFile::DyLibUsed dylibInfo;
-                               dylibInfo.reader = it->second;
-                               std::map<ObjectFile::Reader*,LibraryOptions>::iterator pos = fDylibOptionsMap.find(it->second);
-                               if ( pos != fDylibOptionsMap.end() ) {
-                                       dylibInfo.options = pos->second;
-                               }
-                               else {
-                                       dylibInfo.options.fWeakImport = false;          // FIX ME
-                                       dylibInfo.options.fReExport = false;
-                                       dylibInfo.options.fBundleLoader = false;
-                               }
-                               dynamicLibraries.push_back(dylibInfo);
-                       }
-               }
-       }
-       if ( fBundleLoaderReader != NULL ) {
-               ExecutableFile::DyLibUsed dylibInfo;
-               dylibInfo.reader = fBundleLoaderReader;
-               dylibInfo.options.fWeakImport = false;          
-               dylibInfo.options.fReExport = false;
-               dylibInfo.options.fBundleLoader = true;
-               dynamicLibraries.push_back(dylibInfo);
-       }
-
-       const char* path = fOptions.getOutputFilePath();
-       switch ( fArchitecture ) {
-               case CPU_TYPE_POWERPC:
-                       this->setOutputFile(new mach_o::executable::Writer<ppc>(path, fOptions, dynamicLibraries));
-                       break;
-               case CPU_TYPE_POWERPC64:
-                       this->setOutputFile(new mach_o::executable::Writer<ppc64>(path, fOptions, dynamicLibraries));
-                       break;
-               case CPU_TYPE_I386:
-                       this->setOutputFile(new mach_o::executable::Writer<x86>(path, fOptions, dynamicLibraries));
-                       break;
-               case CPU_TYPE_X86_64:
-                       this->setOutputFile(new mach_o::executable::Writer<x86_64>(path, fOptions, dynamicLibraries));
-                       break;
-               case CPU_TYPE_ARM:
-                       this->setOutputFile(new mach_o::executable::Writer<arm>(path, fOptions, dynamicLibraries));
-                       break;
-               default:
-                       throw "unknown architecture";
-       }
-}
-
-
-Linker::SymbolTable::SymbolTable(Linker& owner)
- : fOwner(owner), fRequireCount(0), fHasExternalTentativeDefinitions(false), fHasExternalWeakDefinitions(false)
-{
-}
-
-void Linker::SymbolTable::require(const char* name)
-{
-       //fprintf(stderr, "require(%s)\n", name);
-       Mapper::iterator pos = fTable.find(name);
-       if ( pos == fTable.end() ) {
-               fTable[name] = NULL;
-               ++fRequireCount;
-       }
-}
-
-// convenience labels for 2-dimensional switch statement
-enum AllDefinitionCombinations {
-       kRegAndReg                              = (ObjectFile::Atom::kRegularDefinition << 3)   | ObjectFile::Atom::kRegularDefinition,
-       kRegAndWeak                             = (ObjectFile::Atom::kRegularDefinition << 3)   | ObjectFile::Atom::kWeakDefinition,
-       kRegAndTent                             = (ObjectFile::Atom::kRegularDefinition << 3)   | ObjectFile::Atom::kTentativeDefinition,
-       kRegAndExtern                   = (ObjectFile::Atom::kRegularDefinition << 3)   | ObjectFile::Atom::kExternalDefinition,
-       kRegAndExternWeak               = (ObjectFile::Atom::kRegularDefinition << 3)   | ObjectFile::Atom::kExternalWeakDefinition,
-       kRegAndAbsolute                 = (ObjectFile::Atom::kRegularDefinition << 3)   | ObjectFile::Atom::kAbsoluteSymbol,
-       kWeakAndReg                             = (ObjectFile::Atom::kWeakDefinition << 3)              | ObjectFile::Atom::kRegularDefinition,
-       kWeakAndWeak                    = (ObjectFile::Atom::kWeakDefinition << 3)              | ObjectFile::Atom::kWeakDefinition,
-       kWeakAndTent                    = (ObjectFile::Atom::kWeakDefinition << 3)              | ObjectFile::Atom::kTentativeDefinition,
-       kWeakAndExtern                  = (ObjectFile::Atom::kWeakDefinition << 3)              | ObjectFile::Atom::kExternalDefinition,
-       kWeakAndExternWeak              = (ObjectFile::Atom::kWeakDefinition << 3)              | ObjectFile::Atom::kExternalWeakDefinition,
-       kWeakAndAbsolute                = (ObjectFile::Atom::kWeakDefinition << 3)              | ObjectFile::Atom::kAbsoluteSymbol,
-       kTentAndReg                             = (ObjectFile::Atom::kTentativeDefinition << 3) | ObjectFile::Atom::kRegularDefinition,
-       kTentAndWeak                    = (ObjectFile::Atom::kTentativeDefinition << 3) | ObjectFile::Atom::kWeakDefinition,
-       kTentAndTent                    = (ObjectFile::Atom::kTentativeDefinition << 3) | ObjectFile::Atom::kTentativeDefinition,
-       kTentAndExtern                  = (ObjectFile::Atom::kTentativeDefinition << 3) | ObjectFile::Atom::kExternalDefinition,
-       kTentAndExternWeak              = (ObjectFile::Atom::kTentativeDefinition << 3) | ObjectFile::Atom::kExternalWeakDefinition,
-       kTentAndAbsolute                = (ObjectFile::Atom::kTentativeDefinition << 3) | ObjectFile::Atom::kAbsoluteSymbol,
-       kExternAndReg                   = (ObjectFile::Atom::kExternalDefinition << 3)  | ObjectFile::Atom::kRegularDefinition,
-       kExternAndWeak                  = (ObjectFile::Atom::kExternalDefinition << 3)  | ObjectFile::Atom::kWeakDefinition,
-       kExternAndTent                  = (ObjectFile::Atom::kExternalDefinition << 3)  | ObjectFile::Atom::kTentativeDefinition,
-       kExternAndExtern                = (ObjectFile::Atom::kExternalDefinition << 3)  | ObjectFile::Atom::kExternalDefinition,
-       kExternAndExternWeak    = (ObjectFile::Atom::kExternalDefinition << 3)  | ObjectFile::Atom::kExternalWeakDefinition,
-       kExternAndAbsolute              = (ObjectFile::Atom::kExternalDefinition << 3)  | ObjectFile::Atom::kAbsoluteSymbol,
-       kExternWeakAndReg               = (ObjectFile::Atom::kExternalWeakDefinition << 3) | ObjectFile::Atom::kRegularDefinition,
-       kExternWeakAndWeak              = (ObjectFile::Atom::kExternalWeakDefinition << 3) | ObjectFile::Atom::kWeakDefinition,
-       kExternWeakAndTent              = (ObjectFile::Atom::kExternalWeakDefinition << 3) | ObjectFile::Atom::kTentativeDefinition,
-       kExternWeakAndExtern    = (ObjectFile::Atom::kExternalWeakDefinition << 3) | ObjectFile::Atom::kExternalDefinition,
-       kExternWeakAndExternWeak= (ObjectFile::Atom::kExternalWeakDefinition << 3) | ObjectFile::Atom::kExternalWeakDefinition,
-       kExternWeakAndAbsolute  = (ObjectFile::Atom::kExternalWeakDefinition << 3) | ObjectFile::Atom::kAbsoluteSymbol,
-       kAbsoluteAndReg                 = (ObjectFile::Atom::kAbsoluteSymbol << 3)              | ObjectFile::Atom::kRegularDefinition,
-       kAbsoluteAndWeak                = (ObjectFile::Atom::kAbsoluteSymbol << 3)              | ObjectFile::Atom::kWeakDefinition,
-       kAbsoluteAndTent                = (ObjectFile::Atom::kAbsoluteSymbol << 3)              | ObjectFile::Atom::kTentativeDefinition,
-       kAbsoluteAndExtern              = (ObjectFile::Atom::kAbsoluteSymbol << 3)              | ObjectFile::Atom::kExternalDefinition,
-       kAbsoluteAndExternWeak  = (ObjectFile::Atom::kAbsoluteSymbol << 3)              | ObjectFile::Atom::kExternalWeakDefinition,
-       kAbsoluteAndAbsolute    = (ObjectFile::Atom::kAbsoluteSymbol << 3)              | ObjectFile::Atom::kAbsoluteSymbol
-};
-
-bool Linker::SymbolTable::add(ObjectFile::Atom& newAtom)
-{
-       bool useNew = true;
-       bool checkVisibilityMismatch = false;
-       const char* name = newAtom.getName();
-       //fprintf(stderr, "map.add(%s => %p from %s)\n", name, &newAtom, newAtom.getFile()->getPath());
-       Mapper::iterator pos = fTable.find(name);
-       ObjectFile::Atom* existingAtom = NULL;
-       if ( pos != fTable.end() )
-               existingAtom = pos->second;
-       if ( existingAtom != NULL ) {
-               // already have atom with same name in symbol table
-               switch ( (AllDefinitionCombinations)((existingAtom->getDefinitionKind() << 3) | newAtom.getDefinitionKind()) ) {
-                       case kRegAndReg:
-                               throwf("duplicate symbol %s in %s and %s", name, newAtom.getFile()->getPath(), existingAtom->getFile()->getPath());
-                       case kRegAndWeak:
-                               // ignore new weak atom, because we already have a non-weak one
-                               useNew = false;
-                               break;
-                       case kRegAndTent:
-                               // ignore new tentative atom, because we already have a regular one
-                               useNew = false;
-                               checkVisibilityMismatch = true;
-                               if ( newAtom.getSize() > existingAtom->getSize() ) {
-                                       warning("for symbol %s tentative definition of size %llu from %s is "
-                                                                       "is smaller than the real definition of size %llu from %s",
-                                                                       newAtom.getDisplayName(), newAtom.getSize(), newAtom.getFile()->getPath(),
-                                                                       existingAtom->getSize(), existingAtom->getFile()->getPath());
-                               }
-                               break;
-                       case kRegAndExtern:
-                               // ignore external atom, because we already have a one
-                               useNew = false;
-                               break;
-                       case kRegAndExternWeak:
-                               // ignore external atom, because we already have a one
-                               useNew = false;
-                               break;
-                       case kRegAndAbsolute:
-                               throwf("duplicate symbol %s in %s and %s", name, newAtom.getFile()->getPath(), existingAtom->getFile()->getPath());
-                               break;
-                       case kWeakAndReg:
-                               // replace existing weak atom with regular one
-                               break;
-                       case kWeakAndWeak:
-                               // have another weak atom, use whichever has largest alignment requirement
-                               // because codegen of some client may require alignment
-                               useNew = ( newAtom.getAlignment().trailingZeros() > existingAtom->getAlignment().trailingZeros() );
-                               checkVisibilityMismatch = true;
-                               break;
-                       case kWeakAndTent:
-                               // replace existing weak atom with tentative one ???
-                               break;
-                       case kWeakAndExtern:
-                               // keep weak atom, at runtime external one may override
-                               useNew = false;
-                               break;
-                       case kWeakAndExternWeak:
-                               // keep weak atom, at runtime external one may override
-                               useNew = false;
-                               break;
-                       case kWeakAndAbsolute:
-                               // replace existing weak atom with absolute one
-                               break;
-                       case kTentAndReg:
-                               // replace existing tentative atom with regular one
-                               checkVisibilityMismatch = true;
-                               if ( newAtom.getSize() < existingAtom->getSize() ) {
-                                       warning("for symbol %s tentative definition of size %llu from %s is "
-                                                                       "being replaced by a real definition of size %llu from %s",
-                                                                       newAtom.getDisplayName(), existingAtom->getSize(), existingAtom->getFile()->getPath(),
-                                                                       newAtom.getSize(), newAtom.getFile()->getPath());
-                               }
-                               break;
-                       case kTentAndWeak:
-                               // replace existing tentative atom with weak one ???
-                               break;
-                       case kTentAndTent:
-                               // use largest
-                               checkVisibilityMismatch = true;
-                               if ( newAtom.getSize() < existingAtom->getSize() ) {
-                                       useNew = false;
-                               } 
-                               else {
-                                       if ( newAtom.getAlignment().trailingZeros() < existingAtom->getAlignment().trailingZeros() )
-                                               warning("alignment lost in merging tentative definition %s", newAtom.getDisplayName());
-                               }
-                               break;
-                       case kTentAndExtern:
-                       case kTentAndExternWeak:
-                               // a tentative definition and a dylib definition, so commons-mode decides how to handle
-                               switch ( fOwner.fOptions.commonsMode() ) {
-                                       case Options::kCommonsIgnoreDylibs:
-                                               if ( fOwner.fOptions.warnCommons() )
-                                                       warning("using common symbol %s from %s and ignoring defintion from dylib %s",
-                                                                       existingAtom->getName(), existingAtom->getFile()->getPath(), newAtom.getFile()->getPath());
-                                               useNew = false;
-                                               break;
-                                       case Options::kCommonsOverriddenByDylibs:
-                                               if ( fOwner.fOptions.warnCommons() )
-                                                       warning("replacing common symbol %s from %s with true definition from dylib %s",
-                                                                       existingAtom->getName(), existingAtom->getFile()->getPath(), newAtom.getFile()->getPath());
-                                               break;
-                                       case Options::kCommonsConflictsDylibsError:
-                                               throwf("common symbol %s from %s conflicts with defintion from dylib %s",
-                                                               existingAtom->getName(), existingAtom->getFile()->getPath(), newAtom.getFile()->getPath());
-                               }
-                               break;
-                       case kTentAndAbsolute:
-                               // replace tentative with absolute (can't size check because absolutes have no size)
-                               break;
-                       case kExternAndReg:
-                               // replace external atom with regular one
-                               break;
-                       case kExternAndWeak:
-                               // replace external atom with weak one
-                               break;
-                       case kExternAndTent:
-                               // a tentative definition and a dylib definition, so commons-mode decides how to handle
-                               switch ( fOwner.fOptions.commonsMode() ) {
-                                       case Options::kCommonsIgnoreDylibs:
-                                               if ( fOwner.fOptions.warnCommons() )
-                                                       warning("using common symbol %s from %s and ignoring defintion from dylib %s",
-                                                                       newAtom.getName(), newAtom.getFile()->getPath(), existingAtom->getFile()->getPath());
-                                               break;
-                                       case Options::kCommonsOverriddenByDylibs:
-                                               if ( fOwner.fOptions.warnCommons() )
-                                                       warning("replacing defintion of %s from dylib %s with common symbol from %s",
-                                                                       newAtom.getName(), existingAtom->getFile()->getPath(), newAtom.getFile()->getPath());
-                                               useNew = false;
-                                               break;
-                                       case Options::kCommonsConflictsDylibsError:
-                                               throwf("common symbol %s from %s conflicts with defintion from dylib %s",
-                                                                       newAtom.getName(), newAtom.getFile()->getPath(), existingAtom->getFile()->getPath());
-                               }
-                               break;
-                       case kExternAndExtern:
-                               throwf("duplicate symbol %s in %s and %s\n", name, newAtom.getFile()->getPath(), existingAtom->getFile()->getPath());
-                       case kExternAndExternWeak:
-                               // keep strong dylib atom, ignore weak one
-                               useNew = false;
-                               break;
-                       case kExternAndAbsolute:
-                               // replace external atom with absolute one
-                               break;
-                       case kExternWeakAndReg:
-                               // replace existing weak external with regular
-                               break;
-                       case kExternWeakAndWeak:
-                               // replace existing weak external with weak (let dyld decide at runtime which to use)
-                               break;
-                       case kExternWeakAndTent:
-                               // a tentative definition and a dylib definition, so commons-mode decides how to handle
-                               switch ( fOwner.fOptions.commonsMode() ) {
-                                       case Options::kCommonsIgnoreDylibs:
-                                               if ( fOwner.fOptions.warnCommons() )
-                                                       warning("using common symbol %s from %s and ignoring defintion from dylib %s",
-                                                                       newAtom.getName(), newAtom.getFile()->getPath(), existingAtom->getFile()->getPath());
-                                               break;
-                                       case Options::kCommonsOverriddenByDylibs:
-                                               if ( fOwner.fOptions.warnCommons() )
-                                                       warning("replacing defintion of %s from dylib %s with common symbol from %s",
-                                                                       newAtom.getName(), existingAtom->getFile()->getPath(), newAtom.getFile()->getPath());
-                                               useNew = false;
-                                               break;
-                                       case Options::kCommonsConflictsDylibsError:
-                                               throwf("common symbol %s from %s conflicts with defintion from dylib %s",
-                                                                       newAtom.getName(), newAtom.getFile()->getPath(), existingAtom->getFile()->getPath());
-                               }
-                               break;
-                       case kExternWeakAndExtern:
-                               // replace existing weak external with external
-                               break;
-                       case kExternWeakAndExternWeak:
-                               // keep existing external weak
-                               useNew = false;
-                               break;
-                       case kExternWeakAndAbsolute:
-                               // replace existing weak external with absolute
-                               break;
-                       case kAbsoluteAndReg:
-                               throwf("duplicate symbol %s in %s and %s", name, newAtom.getFile()->getPath(), existingAtom->getFile()->getPath());
-                       case kAbsoluteAndWeak:
-                               // ignore new weak atom, because we already have a non-weak one
-                               useNew = false;
-                               break;
-                       case kAbsoluteAndTent:
-                               // ignore new tentative atom, because we already have a regular one
-                               useNew = false;
-                               break;
-                       case kAbsoluteAndExtern:
-                               // ignore external atom, because we already have a one
-                               useNew = false;
-                               break;
-                       case kAbsoluteAndExternWeak:
-                               // ignore external atom, because we already have a one
-                               useNew = false;
-                               break;
-                       case kAbsoluteAndAbsolute:
-                               throwf("duplicate symbol %s in %s and %s", name, newAtom.getFile()->getPath(), existingAtom->getFile()->getPath());
-                               break;
-               }
-       }
-       if ( (existingAtom != NULL) && checkVisibilityMismatch && (newAtom.getScope() != existingAtom->getScope()) ) {
-               warning("%s has different visibility (%s) in %s and (%s) in %s", 
-                       newAtom.getDisplayName(), (newAtom.getScope() == 1 ? "hidden" : "default"), newAtom.getFile()->getPath(), (existingAtom->getScope()  == 1 ? "hidden" : "default"), existingAtom->getFile()->getPath());
-       }
-       if ( useNew ) {
-               fTable[name] = &newAtom;
-               if ( existingAtom != NULL ) {
-                       fOwner.markDead(existingAtom);
-                       if ( fOwner.fInitialLoadsDone ) {
-                               //fprintf(stderr, "existing %p %s overridden by %p\n", existingAtom, existingAtom->getName(), &newAtom);
-                               fOwner.fAtomsOverriddenByLateLoads.insert(existingAtom);
-                       }
-               }
-               if ( newAtom.getScope() == ObjectFile::Atom::scopeGlobal ) {
-                       switch ( newAtom.getDefinitionKind() ) {
-                               case ObjectFile::Atom::kTentativeDefinition:
-                                       fHasExternalTentativeDefinitions = true;
-                                       ++fRequireCount; // added a tentative definition means loadUndefines() needs to continue
-                                       break;
-                               case ObjectFile::Atom::kWeakDefinition:
-                                       if ( newAtom.getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableIn )
-                                               fHasExternalWeakDefinitions = true;
-                                       break;
-                               case ObjectFile::Atom::kExternalDefinition:
-                               case ObjectFile::Atom::kExternalWeakDefinition:
-                                       ++fDylibSymbolCount;
-                                       break;
-                               default:
-                                       break;
-                       }
-               }
-       }
-       else {
-               fOwner.markDead(&newAtom);
-       }
-       return useNew;
-}
-
-
-
-ObjectFile::Atom* Linker::SymbolTable::find(const char* name)
-{
-       Mapper::iterator pos = fTable.find(name);
-       if ( pos != fTable.end() ) {
-               return pos->second;
-       }
-       return NULL;
-}
-
-void   Linker::SymbolTable::erase(const char* name) {
-       fTable.erase(name);
-}
-
-void Linker::SymbolTable::getUndefinesNames(std::vector<const char*>& undefines)
-{
-       for (Mapper::iterator it=fTable.begin(); it != fTable.end(); it++) {
-               if ( it->second == NULL ) {
-                       undefines.push_back(it->first);
-               }
-       }
-}
-
-void Linker::SymbolTable::getTentativesNames(std::vector<const char*>& tents)
-{
-       for (Mapper::iterator it=fTable.begin(); it != fTable.end(); it++) {
-               if ( it->second != NULL ) {
-                       if ( (it->second->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition) 
-                                && (it->second->getScope() == ObjectFile::Atom::scopeGlobal) ) {
-                                   tents.push_back(it->first);
-                       }               
-               }
-       }
-}
-
-
-
-bool Linker::AtomSorter::operator()(const ObjectFile::Atom* left, const ObjectFile::Atom* right)
-{
-       if ( left == right )
-               return false;
-
-       // first sort by section order (which is already sorted by segment)
-       unsigned int leftSectionIndex  =  left->getSection()->getIndex();
-       unsigned int rightSectionIndex = right->getSection()->getIndex();
-       if ( leftSectionIndex != rightSectionIndex)
-               return (leftSectionIndex < rightSectionIndex);
-       
-       // magic section$start symbol always sorts to the start of its section
-       if ( left->getContentType() == ObjectFile::Atom::kSectionStart )
-               return true;
-       if ( right->getContentType() == ObjectFile::Atom::kSectionStart )
-               return false;
-
-       // if a -order_file is specified, then sorting is altered to sort those symbols first
-       if ( fOverriddenOrdinalMap != NULL ) {
-               std::map<const ObjectFile::Atom*, uint32_t>::iterator leftPos  = fOverriddenOrdinalMap->find(left);
-               std::map<const ObjectFile::Atom*, uint32_t>::iterator rightPos = fOverriddenOrdinalMap->find(right);
-               std::map<const ObjectFile::Atom*, uint32_t>::iterator end = fOverriddenOrdinalMap->end();
-               if ( leftPos != end ) {
-                       if ( rightPos != end ) {
-                               // both left and right are overridden, so compare overridden ordinals
-                               return leftPos->second < rightPos->second;
-                       }
-                       else {
-                               // left is overridden and right is not, so left < right
-                               return true;
-                       }
-               }
-               else {
-                       if ( rightPos != end ) {
-                               // right is overridden and left is not, so right < left
-                               return false;
-                       }
-                       else {
-                               // neither are overridden, do default sort
-                               // fall into default sorting below
-                       }
-               }
-       }
-
-       // magic section$end symbol always sorts to the end of its section
-       if ( left->getContentType() == ObjectFile::Atom::kSectionEnd )
-               return false;
-       if ( right->getContentType() == ObjectFile::Atom::kSectionEnd )
-               return true;
-
-       // the __common section can have real or tentative definitions
-       // we want the real ones to sort before tentative ones
-       bool leftIsTent  =  (left->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition);
-       bool rightIsTent =  (right->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition);
-       if ( leftIsTent != rightIsTent )
-               return rightIsTent; 
-       
-       // initializers are auto sorted to start of section
-       if ( !fInitializerSet.empty() ) {
-               bool leftFirst  = (fInitializerSet.count(left) != 0);
-               bool rightFirst = (fInitializerSet.count(right) != 0);
-               if ( leftFirst != rightFirst ) 
-                       return leftFirst;
-       }
-
-       // terminators are auto sorted to end of section
-       if ( !fTerminatorSet.empty() ) {
-               bool leftLast  = (fTerminatorSet.count(left) != 0);
-               bool rightLast = (fTerminatorSet.count(right) != 0);
-               if ( leftLast != rightLast ) 
-                       return rightLast;
-       }
-       
-       // lastly sort by atom ordinal.  this is already sorted by .o order
-       return left->getOrdinal() < right->getOrdinal();
-}
-
-
-int main(int argc, const char* argv[])
-{
-       const char* archName = NULL;
-       bool showArch = false;
-       bool archInferred = false;
-       try {
-               // create linker object given command line arguments
-               Linker ld(argc, argv);
-
-               // save error message prefix
-               archName = ld.architectureName();
-               archInferred = ld.isInferredArchitecture();
-               showArch = ld.showArchitectureInErrors();
-
-               // open all input files
-               ld.createReaders();
-
-               // open output file
-               ld.createWriter();
-
-               // do linking
-               ld.link();
-       }
-       catch (const char* msg) {
-               if ( archInferred )
-                       fprintf(stderr, "ld: %s for inferred architecture %s\n", msg, archName);
-               else if ( showArch )
-                       fprintf(stderr, "ld: %s for architecture %s\n", msg, archName);
-               else
-                       fprintf(stderr, "ld: %s\n", msg);
-               return 1;
-       }
-
-       return 0;
-}
diff --git a/src/ld/ld.hpp b/src/ld/ld.hpp
new file mode 100644 (file)
index 0000000..e5319bb
--- /dev/null
@@ -0,0 +1,710 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2005-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@
+ */
+
+
+#ifndef __LD_HPP__
+#define __LD_HPP__
+
+#include <stdint.h>
+#include <math.h>
+#include <unistd.h>
+#include <assert.h>
+
+#include <vector>
+#include <set>
+
+
+namespace ld {
+
+//
+// ld::File 
+//
+// Abstract base class for all object or library files the linker processes.
+// 
+// forEachAtom() iterates over the Atoms in the order they occur in the file.
+//
+// justInTimeforEachAtom(name) iterates over lazily created Atoms.  For instance if
+// File is a static library, justInTimeforEachAtom() will iterate over the base set
+// of Atoms from the archive member implementing 'name'.
+//
+class File
+{
+public:
+       enum ObjcConstraint { objcConstraintNone, objcConstraintRetainRelease, objcConstraintRetainReleaseOrGC, objcConstraintGC };
+       
+       class AtomHandler {
+       public:
+               virtual                         ~AtomHandler() {}
+               virtual void            doAtom(const class Atom&) = 0;
+               virtual void            doFile(const class File&) = 0;
+       };
+
+                                                                               File(const char* pth, time_t modTime, uint32_t ord)
+                                                                                       : _path(pth), _modTime(modTime), _ordinal(ord) { }
+       virtual                                                         ~File() {}
+                       const char*                                     path() const                    { return _path; }
+                       time_t                                          modificationTime() const{ return _modTime; }
+                       uint32_t                                        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; }
+private:
+       const char*                                                     _path;
+       time_t                                                          _modTime;
+       uint32_t                                                        _ordinal;
+};
+
+
+//
+// minumum OS versions
+//
+enum MacVersionMin { macVersionUnset=0, mac10_4=0x000A0400, mac10_5=0x000A0500, 
+                                               mac10_6=0x000A0600, mac10_7=0x000A0700 };
+enum IPhoneVersionMin { iPhoneVersionUnset=0, iPhone2_0=0x00020000, iPhone3_1=0x00030100, 
+                                               iPhone4_2=0x00040200, iPhone4_3=0x00040300 };
+namespace relocatable {
+       //
+       // ld::relocatable::File 
+       //
+       // 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
+       //
+       // canScatterAtoms() true for all compiler generated code.  Hand written assembly can opt-in
+       // via .subsections_via_symbols directive.  When true it means the linker can break up section
+       // content at symbol boundaries and do optimizations like coalescing, dead code stripping, or
+       // apply order files.
+       //
+       // optimize() used by libLTO to lazily generate code from llvm bit-code files
+       // 
+       class File : public ld::File
+       {
+       public:
+               enum DebugInfoKind { kDebugInfoNone=0, kDebugInfoStabs=1, kDebugInfoDwarf=2, kDebugInfoStabsUUID=3 };
+               struct Stab {
+                       const class Atom*       atom;
+                       uint8_t                         type;
+                       uint8_t                         other;
+                       uint16_t                        desc;
+                       uint32_t                        value;
+                       const char*                     string;
+               };
+
+                                                                                       File(const char* pth, time_t modTime, uint32_t ord)
+                                                                                               : ld::File(pth, modTime, ord) { }
+               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(); }
+               virtual const std::vector<Stab>*        stabs() const = 0;
+               virtual bool                                            canScatterAtoms() const = 0;
+               virtual bool                                            hasLongBranchStubs()            { return false; }
+       };
+} // namespace relocatable
+
+
+namespace dylib {
+
+       //
+       // ld::dylib::File 
+       //
+       // Abstract base class for dynamic shared libraries read by the linker processes.
+       //
+       class File : public ld::File
+       {
+       public:
+               class DylibHandler
+               {
+               public:
+                       virtual                         ~DylibHandler() {}
+                       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),
+                                                                                               _dylibTimeStamp(0), _dylibCurrentVersion(0), _dylibCompatibilityVersion(0),
+                                                                                               _explicitlyLinked(false), _implicitlyLinked(false),
+                                                                                               _lazyLoadedDylib(false), _weakLinked(false), _reExported(false),
+                                                                                               _upward(false), _hasNonWeakImportedSymbols(false), 
+                                                                                               _hasWeakImportedSymbols(false), _dead(false) { }
+                               const char*                                     installPath() const                     { return _dylibInstallPath; }
+                               uint32_t                                        timestamp() const                       { return _dylibTimeStamp; }
+                               uint32_t                                        currentVersion() const          { return _dylibCurrentVersion; }
+                               uint32_t                                        compatibilityVersion() const{ return _dylibCompatibilityVersion; }
+                               void                                            setExplicitlyLinked()           { _explicitlyLinked = true; }
+                               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; }
+                               void                                            setWillBeWeakLinked()                   { _weakLinked = true; }
+                               bool                                            willBeWeakLinked() const                { return _weakLinked ||
+                                                                                                                       (_hasWeakImportedSymbols && !_hasNonWeakImportedSymbols); }
+                               void                                            setWillBeReExported()                   { _reExported = true; }
+                               bool                                            willBeReExported() const                { return _reExported; }
+                               void                                            setWillBeUpwardDylib()                  { _upward = true; }
+                               bool                                            willBeUpwardDylib() const               { return _upward; }
+                               void                                            setUsingNonWeakImportedSymbols(){ _hasNonWeakImportedSymbols = true; }
+                               void                                            setUsingWeakImportedSymbols()   { _hasWeakImportedSymbols = true; }
+                               void                                            setWillBeRemoved(bool value)    { _dead = value; }
+                               bool                                            willRemoved() const                             { return _dead; }
+                               
+               virtual void                                            processIndirectLibraries(DylibHandler* handler, bool addImplicitDylibs) = 0;
+               virtual bool                                            providedExportAtom() const = 0;
+               virtual const char*                                     parentUmbrella() const = 0;
+               virtual const std::vector<const char*>* allowableClients() const = 0;
+               virtual bool                                            hasWeakExternals() const = 0;
+               virtual bool                                            deadStrippable() const = 0;
+               virtual bool                                            hasWeakDefinition(const char* name) const = 0;
+               virtual bool                                            hasPublicInstallName() const = 0;
+       protected:
+               const char*                                                     _dylibInstallPath;
+               uint32_t                                                        _dylibTimeStamp;
+               uint32_t                                                        _dylibCurrentVersion;
+               uint32_t                                                        _dylibCompatibilityVersion;
+               bool                                                            _explicitlyLinked;
+               bool                                                            _implicitlyLinked;
+               bool                                                            _lazyLoadedDylib;
+               bool                                                            _weakLinked;
+               bool                                                            _reExported;
+               bool                                                            _upward;
+               bool                                                            _hasNonWeakImportedSymbols;
+               bool                                                            _hasWeakImportedSymbols;
+               bool                                                            _dead;
+       };
+} // namespace dylib
+
+
+
+//
+// ld::Section
+//
+class Section
+{
+public:
+       enum Type { typeUnclassified, typeCode, typePageZero, typeImportProxies, typeLinkEdit, typeMachHeader, typeStack,
+                               typeLiteral4, typeLiteral8, typeLiteral16, typeConstants, typeTempLTO, 
+                               typeCString, typeNonStdCString, typeCStringPointer, typeUTF16Strings, typeCFString, typeObjC1Classes,
+                               typeCFI, typeLSDA, typeDtraceDOF, typeUnwindInfo, typeObjCClassRefs, typeObjC2CategoryList,
+                               typeZeroFill, typeTentativeDefs, typeLazyPointer, typeStub, typeNonLazyPointer, typeDyldInfo, 
+                               typeLazyDylibPointer, typeStubHelper, typeInitializerPointers, typeTerminatorPointers,
+                               typeStubClose, typeLazyPointerClose, typeAbsoluteSymbols, 
+                               typeTLVDefs, typeTLVZeroFill, typeTLVInitialValues, typeTLVInitializerPointers, typeTLVPointers,
+                               typeFirstSection, typeLastSection };
+
+
+                                       Section(const char* sgName, const char* sctName,
+                                                               Type t, bool hidden=false)
+                                                               : _segmentName(sgName), _sectionName(sctName),
+                                                               _type(t), _hidden(hidden)  {}
+                                       Section(const Section& sect)
+                                                               : _segmentName(sect.segmentName()), _sectionName(sect.sectionName()),
+                                                               _type(sect.type()), _hidden(sect.isSectionHidden())  {}
+                                                               
+       bool                    operator==(const Section& rhs) const { return ( (_hidden==rhs._hidden) &&
+                                                                                                               (strcmp(_segmentName, rhs._segmentName)==0) &&
+                                                                                                               (strcmp(_sectionName, rhs._sectionName)==0) ); }
+       bool                    operator!=(const Section& rhs) const { return ! (*this == rhs); }
+       const char*                     segmentName() const                     { return _segmentName; }
+       const char*                     sectionName() const                     { return _sectionName; }
+       Type                            type() const                            { return _type; }
+       bool                            isSectionHidden() const         { return _hidden; }
+       
+private:
+       const char*                     _segmentName;
+       const char*                     _sectionName;
+       Type                            _type;
+       bool                            _hidden;
+};
+
+
+
+//
+// ld::Fixup
+//
+// A Fixup describes how part of an Atom's content must be fixed up.  For instance,
+// an instruction may contain a displacement to another Atom that must be 
+// fixed up by the linker.  
+//
+// A Fixup my reference another Atom. There are two kinds of references: direct and by-name.  
+// With a direct reference, the target is bound by the File that created it. 
+// For instance a reference to a static would produce a direct reference.  
+// A by-name reference requires the linker to find the target Atom with the 
+// required name in order to be bound.
+//
+// For a link to succeed all Fixup must be bound.
+//
+// A Reference also has a fix-up-offset.  This is the offset into the content of the
+// Atom holding the reference where the fix-up (relocation) will be applied.
+//
+//
+struct Fixup 
+{
+       enum TargetBinding { bindingNone, bindingByNameUnbound, bindingDirectlyBound, bindingByContentBound, bindingsIndirectlyBound };
+       enum Cluster { k1of1, k1of2, k2of2, k1of3, k2of3, k3of3, k1of4, k2of4, k3of4, k4of4, k1of5, k2of5, k3of5, k4of5, k5of5 };
+       enum Kind       {       kindNone, kindNoneFollowOn, 
+                                       // grouping
+                                       kindNoneGroupSubordinate, 
+                                       kindNoneGroupSubordinateFDE, kindNoneGroupSubordinateLSDA, kindNoneGroupSubordinatePersonality,
+                                       // value calculations
+                                       kindSetTargetAddress,
+                                       kindSubtractTargetAddress,
+                                       kindAddAddend,
+                                       kindSubtractAddend,
+                                       kindSetTargetImageOffset,
+                                       kindSetTargetSectionOffset,
+                                       kindSetTargetTLVTemplateOffset,
+                                       // pointer store kinds (of current calculated value)
+                                       kindStore8,
+                                       kindStoreLittleEndian16,
+                                       kindStoreLittleEndianLow24of32,
+                                       kindStoreLittleEndian32,
+                                       kindStoreLittleEndian64,
+                                       kindStoreBigEndian16,
+                                       kindStoreBigEndianLow24of32,
+                                       kindStoreBigEndian32,
+                                       kindStoreBigEndian64,
+                                       // Intel specific store kinds
+                                       kindStoreX86BranchPCRel8, kindStoreX86BranchPCRel32, 
+                                       kindStoreX86PCRel8, kindStoreX86PCRel16,  
+                                       kindStoreX86PCRel32, kindStoreX86PCRel32_1, kindStoreX86PCRel32_2, kindStoreX86PCRel32_4, 
+                                       kindStoreX86PCRel32GOTLoad, kindStoreX86PCRel32GOTLoadNowLEA, kindStoreX86PCRel32GOT, 
+                                       kindStoreX86PCRel32TLVLoad, kindStoreX86PCRel32TLVLoadNowLEA,
+                                       kindStoreX86Abs32TLVLoad, kindStoreX86Abs32TLVLoadNowLEA,
+                                       // ARM specific store kinds
+                                       kindStoreARMBranch24, kindStoreThumbBranch22, 
+                                       kindStoreARMLoad12,
+                                       kindStoreARMLow16, kindStoreARMHigh16, 
+                                       kindStoreThumbLow16, kindStoreThumbHigh16, 
+                                       // PowerPC specific store kinds
+                                       kindStorePPCBranch24, kindStorePPCBranch14,
+                                       kindStorePPCPicLow14, kindStorePPCPicLow16, kindStorePPCPicHigh16AddLow, 
+                                       kindStorePPCAbsLow14, kindStorePPCAbsLow16, kindStorePPCAbsHigh16AddLow, kindStorePPCAbsHigh16, 
+                                       // dtrace probes
+                                       kindDtraceExtra,
+                                       kindStoreX86DtraceCallSiteNop, kindStoreX86DtraceIsEnableSiteClear,
+                                       kindStoreARMDtraceCallSiteNop, kindStoreARMDtraceIsEnableSiteClear,
+                                       kindStoreThumbDtraceCallSiteNop, kindStoreThumbDtraceIsEnableSiteClear,
+                                       kindStorePPCDtraceCallSiteNop, kindStorePPCDtraceIsEnableSiteClear,
+                                       // lazy binding
+                                       kindLazyTarget, kindSetLazyOffset,
+                                       // pointer store combinations
+                                       kindStoreTargetAddressLittleEndian32,   // kindSetTargetAddress + kindStoreLittleEndian32
+                                       kindStoreTargetAddressLittleEndian64,   // kindSetTargetAddress + kindStoreLittleEndian64
+                                       kindStoreTargetAddressBigEndian32,              // kindSetTargetAddress + kindStoreBigEndian32
+                                       kindStoreTargetAddressBigEndian64,              // kindSetTargetAddress + kindStoreBigEndian364
+                                       kindSetTargetTLVTemplateOffsetLittleEndian32,  // kindSetTargetTLVTemplateOffset + kindStoreLittleEndian32
+                                       kindSetTargetTLVTemplateOffsetLittleEndian64,  // kindSetTargetTLVTemplateOffset + kindStoreLittleEndian64
+                                       // Intel value calculation and store combinations
+                                       kindStoreTargetAddressX86PCRel32,               // kindSetTargetAddress + kindStoreX86PCRel32
+                                       kindStoreTargetAddressX86BranchPCRel32, // kindSetTargetAddress + kindStoreX86BranchPCRel32
+                                       kindStoreTargetAddressX86PCRel32GOTLoad,// kindSetTargetAddress + kindStoreX86PCRel32GOTLoad
+                                       kindStoreTargetAddressX86PCRel32GOTLoadNowLEA,// kindSetTargetAddress + kindStoreX86PCRel32GOTLoadNowLEA
+                                       kindStoreTargetAddressX86PCRel32TLVLoad, // kindSetTargetAddress + kindStoreX86PCRel32TLVLoad
+                                       kindStoreTargetAddressX86PCRel32TLVLoadNowLEA, // kindSetTargetAddress + kindStoreX86PCRel32TLVLoadNowLEA
+                                       kindStoreTargetAddressX86Abs32TLVLoad,          // kindSetTargetAddress + kindStoreX86Abs32TLVLoad
+                                       kindStoreTargetAddressX86Abs32TLVLoadNowLEA,    // kindSetTargetAddress + kindStoreX86Abs32TLVLoadNowLEA
+                                       // ARM value calculation and store combinations
+                                       kindStoreTargetAddressARMBranch24,              // kindSetTargetAddress + kindStoreARMBranch24
+                                       kindStoreTargetAddressThumbBranch22,    // kindSetTargetAddress + kindStoreThumbBranch22
+                                       kindStoreTargetAddressARMLoad12,                // kindSetTargetAddress + kindStoreARMLoad12
+                                       // PowerPC value calculation and store combinations
+                                       kindStoreTargetAddressPPCBranch24,              // kindSetTargetAddress + kindStorePPCBranch24
+                       };
+
+       union {
+               const Atom*     target;
+               const char*     name;
+               uint64_t        addend;
+               uint32_t        bindingIndex;
+       } u;
+       uint32_t                offsetInAtom;
+       Kind                    kind : 8;
+       Cluster                 clusterSize : 4;
+       bool                    weakImport : 1;
+       TargetBinding   binding : 3;
+       bool                    contentAddendOnly : 1;
+       bool                    contentDetlaToAddendOnly : 1;
+       
+       typedef Fixup*          iterator;
+
+       Fixup() :
+               offsetInAtom(0), kind(kindNone), clusterSize(k1of1), weakImport(false), 
+               binding(bindingNone),  
+               contentAddendOnly(false), contentDetlaToAddendOnly(false) { u.target = NULL; }
+
+       Fixup(Kind k, Atom* targetAtom) :
+               offsetInAtom(0), kind(k), clusterSize(k1of1), weakImport(false), 
+               binding(Fixup::bindingDirectlyBound),  
+               contentAddendOnly(false), contentDetlaToAddendOnly(false)  
+                       { assert(targetAtom != NULL); u.target = targetAtom; }
+
+       Fixup(uint32_t off, Cluster c, Kind k) :
+               offsetInAtom(off), kind(k), clusterSize(c), weakImport(false), 
+               binding(Fixup::bindingNone),  
+               contentAddendOnly(false), contentDetlaToAddendOnly(false)  
+                       { u.addend = 0; }
+
+       Fixup(uint32_t off, Cluster c, Kind k, bool weakIm, const char* name) :
+               offsetInAtom(off), kind(k), clusterSize(c), weakImport(weakIm), 
+               binding(Fixup::bindingByNameUnbound),  
+               contentAddendOnly(false), contentDetlaToAddendOnly(false) 
+                       { assert(name != NULL); u.name = name; }
+               
+       Fixup(uint32_t off, Cluster c, Kind k, TargetBinding b, const char* name) :
+               offsetInAtom(off), kind(k), clusterSize(c), weakImport(false), binding(b),  
+               contentAddendOnly(false), contentDetlaToAddendOnly(false) 
+                       { assert(name != NULL); u.name = name; }
+               
+       Fixup(uint32_t off, Cluster c, Kind k, const Atom* targetAtom) :
+               offsetInAtom(off), kind(k), clusterSize(c), weakImport(false), 
+               binding(Fixup::bindingDirectlyBound),  
+               contentAddendOnly(false), contentDetlaToAddendOnly(false) 
+                       { assert(targetAtom != NULL); u.target = targetAtom; }
+               
+       Fixup(uint32_t off, Cluster c, Kind k, TargetBinding b, const Atom* targetAtom) :
+               offsetInAtom(off), kind(k), clusterSize(c), weakImport(false), binding(b),  
+               contentAddendOnly(false), contentDetlaToAddendOnly(false) 
+                       { assert(targetAtom != NULL); u.target = targetAtom; }
+               
+       Fixup(uint32_t off, Cluster c, Kind k, uint64_t addend) :
+               offsetInAtom(off), kind(k), clusterSize(c), weakImport(false), 
+               binding(Fixup::bindingNone),  
+               contentAddendOnly(false), contentDetlaToAddendOnly(false) 
+                       { u.addend = addend; }
+                       
+       bool firstInCluster() const { 
+               switch (clusterSize) {
+                       case k1of1:
+                       case k1of2:
+                       case k1of3:
+                       case k1of4:
+                       case k1of5:
+                               return true;
+                       default:
+                               break;
+               }
+               return false;
+       }
+       
+       bool lastInCluster() const { 
+               switch (clusterSize) {
+                       case k1of1:
+                       case k2of2:
+                       case k3of3:
+                       case k4of4:
+                       case k5of5:
+                               return true;
+                       default:
+                               break;
+               }
+               return false;
+       }
+       
+};
+
+//
+// ld::Atom
+//
+// An atom is the fundamental unit of linking.  A C function or global variable is an atom.
+// An atom has content and attributes. The content of a function atom is the instructions
+// that implement the function.  The content of a global variable atom is its initial bits.
+//
+// Name:
+// The name of an atom is the label name generated by the compiler.  A C compiler names foo()
+// as _foo.  A C++ compiler names foo() as __Z3foov.
+// The name refers to the first byte of the content.  An atom cannot have multiple entry points.
+// Such code is modeled as multiple atoms, each having a "follow on" reference to the next.
+// A "follow on" reference is a contraint to the linker to the atoms must be laid out contiguously.
+//
+// Scope:
+// An atom is in one of three scopes: translation-unit, linkage-unit, or global.  These correspond
+// to the C visibility of static, hidden, default.
+//
+// DefinitionKind:
+// An atom is one of five defintion kinds:
+//     regular                 Most atoms.
+//     weak                    C++ compiler makes some functions weak if there might be multiple copies
+//                                     that the linker needs to coalesce.
+//     tentative               A straggler from ancient C when the extern did not exist. "int foo;" is ambiguous.
+//                                     It could be a prototype or it could be a definition.
+//     external                This is a "proxy" atom produced by a dylib reader.  It has no content.  It exists
+//                                     so that the graph of Atoms can be complete.
+//     external-weak   Same as external, but the definition in the dylib is weak.
+//
+// SymbolTableInclusion:
+// An atom may or may not be in the symbol table in an object file.
+//  in                         Most atoms for functions or global data
+//     not-in                  Anonymous atoms such literal c-strings, or other compiler generated data
+//  not-in-final       Atom whose name should not be in the symbol table of final linkd image (e.g. 'l' labels .eh labels)
+//     in-never-strip  Atom whose name the strip tool should never remove (e.g. REFERENCED_DYNAMICALLY in mach-o)
+//
+// ContentType:
+// Some atoms require specially processing by the linker based on their content.  For instance, zero-fill data
+// atom are group together at the end of the DATA segment to reduce disk size.
+//
+// ObjectAddress:
+// For reproducability, the linker lays out atoms in the order they occurred in the source (object) files.
+// The objectAddress() method returns the address of an atom in the object file so that the linker 
+// can arrange the atoms.
+//
+//
+class Atom
+{
+public:
+       enum Scope { scopeTranslationUnit, scopeLinkageUnit, scopeGlobal };
+       enum Definition { definitionRegular, definitionTentative, definitionAbsolute, definitionProxy };
+       enum Combine { combineNever, combineByName, combineByNameAndContent, combineByNameAndReferences };
+       enum ContentType { typeUnclassified, typeZeroFill, typeCString, typeCFI, typeLSDA, typeSectionStart, 
+                                       typeSectionEnd, typeBranchIsland, typeLazyPointer, typeStub, typeNonLazyPointer, 
+                                       typeLazyDylibPointer, typeStubHelper, typeInitializerPointers, typeTerminatorPointers,
+                                       typeLTOtemporary, typeResolver,
+                                       typeTLV, typeTLVZeroFill, typeTLVInitialValue, typeTLVInitializerPointers };
+
+       enum SymbolTableInclusion { symbolTableNotIn, symbolTableNotInFinalLinkedImages, symbolTableIn,
+                                                               symbolTableInAndNeverStrip, symbolTableInAsAbsolute, 
+                                                               symbolTableInWithRandomAutoStripLabel };
+       struct Alignment { 
+                                       Alignment(int p2, int m=0) : powerOf2(p2), modulus(m) {}
+               uint8_t         trailingZeros() const { return (modulus==0) ? powerOf2 : __builtin_ctz(modulus); }
+               uint16_t        powerOf2;  
+               uint16_t        modulus; 
+       };
+       struct LineInfo {
+               const char* fileName;
+               uint32_t        atomOffset;
+               uint32_t        lineNumber;
+               
+               typedef LineInfo* iterator;
+       };
+       struct UnwindInfo {
+               uint32_t        startOffset;
+               uint32_t        unwindInfo;
+               
+               typedef UnwindInfo* iterator;
+       };
+                                                                                       Atom(const Section& sect, Definition d, Combine c, Scope s, ContentType ct, 
+                                                                                               SymbolTableInclusion i, bool dds, bool thumb, bool al, Alignment a) :  
+                                                                                                       _section(&sect), _address(0), _alignmentModulus(a.modulus), 
+                                                                                                       _alignmentPowerOf2(a.powerOf2), _definition(d), _combine(c),   
+                                                                                                       _dontDeadStrip(dds), _thumb(thumb), _alias(al), _autoHide(false), 
+                                                                                                       _contentType(ct), _symbolTableInclusion(i),
+                                                                                                       _scope(s), _mode(modeSectionOffset), 
+                                                                                                       _overridesADylibsWeakDef(false), _coalescedAway(false),
+                                                                                                       _weakImport(false), _live(false), _machoSection(0)
+                                                                                                        {
+                                                                                                       #ifndef NDEBUG
+                                                                                                               switch ( _combine ) {
+                                                                                                                       case combineByNameAndContent:
+                                                                                                                       case combineByNameAndReferences:
+                                                                                                                               assert(_symbolTableInclusion == symbolTableNotIn);
+                                                                                                                               assert(_scope != scopeGlobal);
+                                                                break;
+                                                            case combineByName:
+                                                            case combineNever:
+                                                                break;
+                                                                                                               };
+                                                                                                       #endif
+                                                                                                        }
+       virtual                                                                 ~Atom() {}
+
+       const Section&                                                  section() const                         { return *_section; }
+       Definition                                                              definition() const                      { return _definition; }
+       Combine                                                                 combine() const                         { return _combine; }
+       Scope                                                                   scope() const                           { return _scope; }
+       ContentType                                                             contentType() const                     { return _contentType; }
+       SymbolTableInclusion                                    symbolTableInclusion() const{ return _symbolTableInclusion; }
+       bool                                                                    dontDeadStrip() const           { return _dontDeadStrip; }
+       bool                                                                    isThumb() const                         { return _thumb; }
+       bool                                                                    isAlias() const                         { return _alias; }
+       Alignment                                                               alignment() const                       { return Alignment(_alignmentPowerOf2, _alignmentModulus); }
+       bool                                                                    overridesDylibsWeakDef() const  { return _overridesADylibsWeakDef; }
+       bool                                                                    coalescedAway() const           { return _coalescedAway; }
+       bool                                                                    weakImported() const            { return _weakImport; }
+       bool                                                                    autoHide() const                        { return _autoHide; }
+       bool                                                                    live() const                            { return _live; }
+       uint8_t                                                                 machoSection() const            { assert(_machoSection != 0); return _machoSection; }
+
+       void                                                                    setScope(Scope s)                       { _scope = s; }
+       void                                                                    setSymbolTableInclusion(SymbolTableInclusion i)                 
+                                                                                                                                               { _symbolTableInclusion = i; }
+       void                                                                    setCombine(Combine c)           { _combine = c; }
+       void                                                                    setOverridesDylibsWeakDef()     { _overridesADylibsWeakDef = true; }
+       void                                                                    setCoalescedAway()                      { _coalescedAway = true; }
+       void                                                                    setWeakImported()                       { _weakImport = true; assert(_definition == definitionProxy); }
+       void                                                                    setAutoHide()                           { _autoHide = true; }
+       void                                                                    setLive()                                       { _live = true; }
+       void                                                                    setLive(bool value)                     { _live = value; }
+       void                                                                    setMachoSection(unsigned x) { assert(x != 0); assert(x < 256); _machoSection = x; }
+       void                                                                    setSectionOffset(uint64_t o){ assert(_mode == modeSectionOffset); _address = o; _mode = modeSectionOffset; }
+       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; }
+
+       virtual const File*                                             file() const = 0;
+       virtual bool                                                    translationUnitSource(const char** dir, const char** name) const = 0;
+       virtual const char*                                             name() const = 0;
+       virtual uint64_t                                                objectAddress() const = 0;
+       virtual uint64_t                                                size() const = 0;
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const = 0;
+       virtual const uint8_t*                                  rawContentPointer() const { return NULL; }
+       virtual unsigned long                                   contentHash(const class IndirectBindingTable&) const { return 0; }
+       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; }
+       virtual UnwindInfo::iterator                    beginUnwind() const { return NULL; }
+       virtual UnwindInfo::iterator                    endUnwind() const       { return NULL; }
+       virtual LineInfo::iterator                              beginLineInfo() const { return NULL; }
+       virtual LineInfo::iterator                              endLineInfo() const { return NULL; }
+                                                                                       
+protected:
+       enum AddressMode { modeSectionOffset, modeFinalAddress };
+
+                                                                                       void setAttributesFromAtom(const Atom& a) { 
+                                                                                                       _section = a._section; 
+                                                                                                       _alignmentModulus = a._alignmentModulus;
+                                                                                                       _alignmentPowerOf2 = a._alignmentPowerOf2;
+                                                                                                       _definition = a._definition;
+                                                                                                       _combine = a._combine;
+                                                                                                       _dontDeadStrip = a._dontDeadStrip;
+                                                                                                       _thumb = a._thumb;
+                                                                                                       _alias = a._alias;
+                                                                                                       _autoHide = a._autoHide;
+                                                                                                       _contentType = a._contentType;
+                                                                                                       _symbolTableInclusion = a._symbolTableInclusion;
+                                                                                                       _scope = a._scope;
+                                                                                                       _mode = a._mode;
+                                                                                                       _overridesADylibsWeakDef = a._overridesADylibsWeakDef;
+                                                                                                       _coalescedAway = a._coalescedAway;
+                                                                                                       _weakImport = a._weakImport;
+                                                                                               }
+
+       const Section *                                         _section;
+       uint64_t                                                        _address;
+       uint16_t                                                        _alignmentModulus;
+       uint8_t                                                         _alignmentPowerOf2;
+       Definition                                                      _definition : 2;
+       Combine                                                         _combine : 2;
+       bool                                                            _dontDeadStrip : 1;
+       bool                                                            _thumb : 1; 
+       bool                                                            _alias : 1;
+       int                                                                     _autoHide : 1;
+       ContentType                                                     _contentType : 5;
+       SymbolTableInclusion                            _symbolTableInclusion : 3;
+       Scope                                                           _scope : 2;
+       AddressMode                                                     _mode: 2;
+       bool                                                            _overridesADylibsWeakDef : 1;
+       bool                                                            _coalescedAway : 1;
+       bool                                                            _weakImport : 1;
+       bool                                                            _live : 1;
+       unsigned                                                        _machoSection : 8;
+};
+
+
+class IndirectBindingTable
+{
+public:        
+       virtual const char*                     indirectName(uint32_t bindingIndex) const = 0;
+       virtual const ld::Atom*         indirectAtom(uint32_t bindingIndex) const = 0;
+};
+
+
+class Internal
+{
+public:
+       class FinalSection : public ld::Section {
+       public:
+                                                                               FinalSection(const Section& sect) : Section(sect), address(0),
+                                                                                               fileOffset(0), size(0), alignment(0),
+                                                                                               indirectSymTabStartIndex(0), indirectSymTabElementSize(0),
+                                                                                               relocStart(0), relocCount(0), 
+                                                                                               hasLocalRelocs(false), hasExternalRelocs(false) {}
+               std::vector<const Atom*>                atoms;
+               uint64_t                                                address;
+               uint64_t                                                fileOffset;
+               uint64_t                                                size;
+               uint32_t                                                alignmentPaddingBytes;
+               uint8_t                                                 alignment;
+               uint32_t                                                indirectSymTabStartIndex;
+               uint32_t                                                indirectSymTabElementSize;
+               uint32_t                                                relocStart;
+               uint32_t                                                relocCount;
+               bool                                                    hasLocalRelocs;
+               bool                                                    hasExternalRelocs;
+       };
+       
+       virtual ld::Internal::FinalSection*     addAtom(const Atom&) = 0;
+       virtual ld::Internal::FinalSection* getFinalSection(const ld::Section& inputSection) = 0;
+       virtual                                                         ~Internal() {}
+                                                                               Internal() : bundleLoader(NULL),
+                                                                                       entryPoint(NULL), classicBindingHelper(NULL),
+                                                                                       lazyBindingHelper(NULL), compressedFastBinderProxy(NULL),
+                                                                                       objcObjectConstraint(ld::File::objcConstraintNone), 
+                                                                                       objcDylibConstraint(ld::File::objcConstraintNone), 
+                                                                                       cpuSubType(0), 
+                                                                                       allObjectFilesScatterable(true), hasObjcReplacementClasses(false),
+                                                                                       someObjectFileHasDwarf(false), usingHugeSections(false) { }
+                                                                               
+       std::vector<FinalSection*>                                      sections;
+       std::vector<ld::dylib::File*>                           dylibs;
+       std::vector<ld::relocatable::File::Stab>        stabs;
+       std::vector<const ld::Atom*>                            indirectBindingTable;
+       const ld::dylib::File*                                          bundleLoader;
+       const Atom*                                                                     entryPoint;
+       const Atom*                                                                     classicBindingHelper;
+       const Atom*                                                                     lazyBindingHelper;
+       const Atom*                                                                     compressedFastBinderProxy;
+       ld::File::ObjcConstraint                                        objcObjectConstraint;
+       ld::File::ObjcConstraint                                        objcDylibConstraint;
+       uint32_t                                                                        cpuSubType;
+       bool                                                                            allObjectFilesScatterable;
+       bool                                                                            hasObjcReplacementClasses;
+       bool                                                                            someObjectFileHasDwarf;
+       bool                                                                            usingHugeSections;
+};
+
+
+
+
+
+
+
+
+
+
+
+
+} // namespace ld 
+
+#endif // __LD_HPP__
diff --git a/src/ld/lto_file.hpp b/src/ld/lto_file.hpp
new file mode 100644 (file)
index 0000000..24d3f58
--- /dev/null
@@ -0,0 +1,642 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006-2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __LTO_READER_H__
+#define __LTO_READER_H__
+
+#include <stdlib.h>
+#include <mach-o/dyld.h>
+#include <vector>
+#include <ext/hash_set>
+#include <ext/hash_map>
+
+#include "MachOFileAbstraction.hpp"
+#include "Architectures.hpp"
+#include "ld.hpp"
+
+#include "llvm-c/lto.h"
+
+
+namespace lto {
+         
+
+//
+// ld64 only tracks non-internal symbols from an llvm bitcode file.  
+// We model this by having an InternalAtom which represent all internal functions and data.
+// All non-interal symbols from a bitcode file are represented by an Atom
+// and each Atom has a reference to the InternalAtom.  The InternalAtom
+// also has references to each symbol external to the bitcode file. 
+//
+class InternalAtom : public ld::Atom
+{
+public:
+                                                                                               InternalAtom(class File& f);
+       // overrides of ld::Atom
+       virtual ld::File*                                                       file() const            { return &_file; }
+       virtual bool                                                            translationUnitSource(const char** dir, const char** nm) const
+                                                                                                                                       { return false; }
+       virtual const char*                                                     name() const            { return "import-atom"; }
+       virtual uint64_t                                                        size() const            { return 0; }
+       virtual uint64_t                                                        objectAddress() const { return 0; }
+       virtual void                                                            copyRawContent(uint8_t buffer[]) const { }
+       virtual void                                                            setScope(Scope)         { }
+       virtual ld::Fixup::iterator                                     fixupsBegin()           { return &_undefs[0]; }
+       virtual ld::Fixup::iterator                                     fixupsEnd()                     { return &_undefs[_undefs.size()]; }
+
+       // for adding references to symbols outside bitcode file
+       void                                                                            addReference(const char* name)
+                                                                                                                                       { _undefs.push_back(ld::Fixup(0, ld::Fixup::k1of1, 
+                                                                                                                                                               ld::Fixup::fixupNone, false, name)); }
+private:
+
+       ld::File&                                                                       _file;
+       std::vector<ld::Fixup>                                          _undefs;
+};
+
+
+//
+// LLVM bitcode file 
+//
+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);
+       virtual                                                                 ~File();
+
+       // overrides of ld::File
+       virtual bool                                                                            forEachAtom(ld::File::AtomHandler&);
+       virtual bool                                                                            justInTimeforEachAtom(const char* name, ld::File::AtomHandler&) 
+                                                                                                                                                                       { return false; }
+       
+       // overrides of ld::relocatable::File 
+       virtual bool                                                                            objcReplacementClasses()        { return false; }
+       virtual DebugInfoKind                                                           debugInfo()                                     { return ld::relocatable::File::kDebugInfoNone; }
+       virtual std::vector<ld::relocatable::File::Stab>*       stabs()                                         { return NULL; }
+       virtual bool                                                                            canScatterAtoms()                       { return true; }
+
+       lto_module_t                                                                            module()                                        { return _module; }
+       class InternalAtom&                                                                     internalAtom()                          { return _internalAtom; }
+private:
+       friend class Atom;
+       friend class InternalAtom;
+       
+       cpu_type_t                                                              _architecture;
+       class InternalAtom                                              _internalAtom;
+       class Atom*                                                             _atomArray;
+       uint32_t                                                                _atomArrayCount;
+       lto_module_t                                                    _module;
+       ld::Section                                                             _section;
+};
+
+//
+// Atom acts as a proxy Atom for the symbols that are exported by LLVM bitcode file. Initially,
+// Reader creates Atoms to allow linker proceed with usual symbol resolution phase. After
+// optimization is performed, real Atoms are created for these symobls. However these real Atoms
+// are not inserted into global symbol table. Atom holds real Atom and forwards appropriate
+// methods to real atom.
+//
+class Atom : public ld::Atom
+{
+public:
+                                                                               Atom(File& f, const char* name, ld::Atom::Scope s, 
+                                                                                                       ld::Atom::Definition d, ld::Atom::Alignment a);
+
+       // overrides of ld::Atom
+       virtual ld::File*                                       file() const            { return &_file; }
+       virtual bool                                            translationUnitSource(const char** dir, const char** nm) const
+                                                                                                                       { return (_compiledAtom ? _compiledAtom->translationUnitSource(dir, nm) : false); }
+       virtual const char*                                     name() const            { return _name; }
+       virtual uint64_t                                        size() const            { return (_compiledAtom ? _compiledAtom->size() : 0); }
+       virtual uint64_t                                        objectAddress() const { return (_compiledAtom ? _compiledAtom->objectAddress() : 0); }
+       virtual void                                            copyRawContent(uint8_t buffer[]) const 
+                                                                                                                       { if (_compiledAtom) _compiledAtom->copyRawContent(buffer); }
+                                                                                                                       
+       ld::Atom*                                                       compiledAtom()          { return _compiledAtom; }
+       void                                                            setCompiledAtom(ld::Atom& atom) 
+                                                                                                                       { _compiledAtom = &atom; }
+private:
+
+       File&                                                           _file;
+       const char*                                                     _name;
+       ld::Atom*                                                       _compiledAtom;
+};
+
+                                                                                       
+
+
+
+
+
+class Parser 
+{
+public:
+       static bool                                             validFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture);
+       static const char*                              fileKind(const uint8_t* fileContent);
+       static File*                                    parse(const uint8_t* fileContent, uint64_t fileLength, const char* path, 
+                                                                                       time_t modTime, uint32_t ordinal, cpu_type_t architecture);
+       static bool                                             libLTOisLoaded() { return (::lto_get_version() != NULL); }
+       static bool                                             optimize(const std::vector<ld::Atom*>& allAtoms, std::vector<ld::Atom*>& newAtoms, 
+                                                                                               std::vector<const char*>& additionalUndefines, 
+                                                                                               const std::set<ld::Atom*>&,
+                                                                                               std::vector<ld::Atom*>& newDeadAtoms,
+                                                                                               uint32_t nextInputOrdinal, 
+                                                                                               ld::OutFile* writer, ld::Atom* entryPointAtom,
+                                                                                               const std::vector<const char*>& llvmOptions,
+                                                                                               bool allGlobalsAReDeadStripRoots,
+                                                                                               bool verbose, bool saveTemps, 
+                                                                                               const char* outputFilePath,
+                                                                                               bool pie,  bool mainExecutable, bool staticExecutable, bool relocatable,
+                                                                                               bool allowTextRelocs, cpu_type_t arch);
+
+       static const char*                      ltoVersion()    { return ::lto_get_version(); }
+
+private:
+       static const char*                              tripletPrefixForArch(cpu_type_t arch);
+       static ld::relocatable::File*   parseMachOFile(const uint8_t* p, size_t len, uint32_t nextInputOrdinal, cpu_type_t arch);
+
+       class CStringEquals
+       {
+       public:
+               bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+       };
+       typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals>  CStringSet;
+       typedef __gnu_cxx::hash_map<const char*, Atom*, __gnu_cxx::hash<const char*>, CStringEquals> CStringToAtom;
+       
+       class AtomSyncer : public ld::File::AtomHandler {
+       public:
+                                                       AtomSyncer(std::vector<const char*>& a, std::vector<ld::Atom*>&na,
+                                                                               CStringToAtom la, CStringToAtom dla) :
+                                                                               additionalUndefines(a), newAtoms(na), llvmAtoms(la), deadllvmAtoms(dla) { }
+               virtual void            doAtom(class ld::Atom&);
+               
+               std::vector<const char*>&               additionalUndefines;
+               std::vector<ld::Atom*>&                 newAtoms;
+               CStringToAtom                                   llvmAtoms;
+               CStringToAtom                                   deadllvmAtoms;
+       };
+
+       static std::vector<File*>               _s_files;
+};
+
+std::vector<File*> Parser::_s_files;
+
+
+const char* Parser::tripletPrefixForArch(cpu_type_t arch)
+{
+       switch (arch) {
+               case CPU_TYPE_POWERPC:
+                       return "powerpc-";
+               case CPU_TYPE_POWERPC64:
+                       return "powerpc64-";
+               case CPU_TYPE_I386:
+                       return "i386-";
+               case CPU_TYPE_X86_64:
+                       return "x86_64-";
+               case CPU_TYPE_ARM:
+                       return "arm";
+       }
+       return "";
+}
+
+bool Parser::validFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture)
+{
+       return ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, tripletPrefixForArch(architecture));
+}
+
+const char* Parser::fileKind(const uint8_t* p)
+{
+       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_POWERPC:
+                               return "ppc";
+                       case CPU_TYPE_I386:
+                               return "i386";
+                       case CPU_TYPE_X86_64:
+                               return "x86_64";
+                       case CPU_TYPE_ARM:
+                               return "arm";
+               }
+               return "unknown bitcode architecture";
+       }
+       return NULL;
+}
+
+File* Parser::parse(const uint8_t* fileContent, uint64_t fileLength, const char* path, time_t modTime, 
+                                                                                                                               uint32_t ordinal, cpu_type_t architecture) 
+{
+       File* f = new File(path, modTime, fileContent, fileLength, ordinal, architecture);
+       _s_files.push_back(f);
+       return f;
+}
+
+
+ld::relocatable::File* Parser::parseMachOFile(const uint8_t* p, size_t len, uint32_t nextInputOrdinal, cpu_type_t arch) 
+{
+       switch ( arch ) {
+               case CPU_TYPE_POWERPC:
+                       if ( mach_o::relocatable::Parser<ppc>::validFile(p) )
+                               return mach_o::relocatable::Parser<ppc>::parse(p, len, "/tmp/lto.o", 0, nextInputOrdinal);
+                       break;
+               case CPU_TYPE_POWERPC64:
+                       if ( mach_o::relocatable::Parser<ppc64>::validFile(p) )
+                               return mach_o::relocatable::Parser<ppc64>::parse(p, len, "/tmp/lto.o", 0, nextInputOrdinal);
+                       break;
+               case CPU_TYPE_I386:
+                       if ( mach_o::relocatable::Parser<x86>::validFile(p) )
+                               return mach_o::relocatable::Parser<x86>::parse(p, len, "/tmp/lto.o", 0, nextInputOrdinal);
+                       break;
+               case CPU_TYPE_X86_64:
+                       if ( mach_o::relocatable::Parser<x86_64>::validFile(p) )
+                               return mach_o::relocatable::Parser<x86_64>::parse(p, len, "/tmp/lto.o", 0, nextInputOrdinal);
+                       break;
+               case CPU_TYPE_ARM:
+                       if ( mach_o::relocatable::Parser<arm>::validFile(p) )
+                               return mach_o::relocatable::Parser<arm>::parse(p, len, "/tmp/lto.o", 0, nextInputOrdinal);
+                       break;
+       }
+       throw "LLVM LTO, file is not of required architecture";
+}
+
+
+
+File::File(const char* path, time_t mTime, const uint8_t* content, uint32_t contentLength, uint32_t ordinal, cpu_type_t arch) 
+       : ld::relocatable::File(path,mTime,ordinal), _architecture(arch), _internalAtom(*this), 
+       _atomArray(NULL), _atomArrayCount(0), _module(NULL),
+       _section("__TEXT_", "__tmp_lto", ld::Section::typeUnclassified)
+{
+       // create llvm module
+       _module = ::lto_module_create_from_memory(content, contentLength);
+    if ( _module == NULL )
+               throwf("could not parse object file %s: %s", path, lto_get_error_message());
+       
+       // create atom for each global symbol in module
+       uint32_t count = ::lto_module_get_num_symbols(_module);
+       _atomArray = (Atom*)malloc(sizeof(Atom)*count);
+       for (uint32_t i=0; i < count; ++i) {
+               const char* name = ::lto_module_get_symbol_name(_module, i);
+               lto_symbol_attributes attr = lto_module_get_symbol_attribute(_module, i);
+
+               // <rdar://problem/6378110> LTO doesn't like dtrace symbols
+               // ignore dtrace static probes for now
+               // later when codegen is done and a mach-o file is produces the probes will be processed
+               if ( (strncmp(name, "___dtrace_probe$", 16) == 0) || (strncmp(name, "___dtrace_isenabled$", 20) == 0) )
+                       continue;
+                               
+               ld::Atom::Definition def;
+               switch ( attr & LTO_SYMBOL_DEFINITION_MASK ) {
+                       case LTO_SYMBOL_DEFINITION_REGULAR:
+                               def = ld::Atom::definitionRegular;
+                               break;
+                       case LTO_SYMBOL_DEFINITION_TENTATIVE:
+                               def = ld::Atom::definitionTentative;
+                               break;
+                       case LTO_SYMBOL_DEFINITION_WEAK:
+                               def = ld::Atom::definitionRegular;
+                               break;
+                       case LTO_SYMBOL_DEFINITION_UNDEFINED:
+                       case LTO_SYMBOL_DEFINITION_WEAKUNDEF:
+                               def = ld::Atom::definitionProxy;
+                               break;
+                       default:
+                               throwf("unknown definition kind for symbol %s in bitcode file %s", name, path);
+               }
+
+               // make LLVM atoms for definitions and a reference for undefines
+               if ( def != ld::Atom::definitionProxy ) {
+                       ld::Atom::Scope scope;
+                       switch ( attr & LTO_SYMBOL_SCOPE_MASK) {
+                               case LTO_SYMBOL_SCOPE_INTERNAL:
+                                       scope = ld::Atom::scopeTranslationUnit;
+                                       break;
+                               case LTO_SYMBOL_SCOPE_HIDDEN:
+                                       scope = ld::Atom::scopeLinkageUnit;
+                                       break;
+                               case LTO_SYMBOL_SCOPE_DEFAULT:
+                                       scope = ld::Atom::scopeGlobal;
+                                       break;
+                               default:
+                                       throwf("unknown scope for symbol %s in bitcode file %s", name, path);
+                       }
+                       // only make atoms for non-internal symbols 
+                       if ( scope == ld::Atom::scopeTranslationUnit )
+                               continue;
+                       uint8_t alignment = (attr & LTO_SYMBOL_ALIGNMENT_MASK);
+                       // make Atom using placement new operator
+                       new (&_atomArray[_atomArrayCount++]) Atom(*this, name, scope, def, alignment);
+               }
+               else {
+                       // add to list of external references
+                       _internalAtom.addReference(name);
+               }
+       }
+}
+
+File::~File()
+{
+       if ( _module != NULL )
+               ::lto_module_dispose(_module);
+}
+
+bool File::forEachAtom(ld::File::AtomHandler& handler)
+{
+       handler.doAtom(_internalAtom);
+       for(uint32_t i=0; i < _atomArrayCount; ++i) {
+               handler.doAtom(_atomArray[i]);
+       }
+       return true;
+}
+
+InternalAtom::InternalAtom(File& f)
+       : ld::Atom(f._section, ld::Atom::definitionRegular, ld::Atom::combineNever, ld::Atom::scopeTranslationUnit, 
+                               ld::Atom::typeLTOtemporary, ld::Atom::symbolTableNotIn, false, false, ld::Atom::Alignment(0)),
+               _file(f)
+{
+}
+
+Atom::Atom(File& f, const char* name, ld::Atom::Scope s, ld::Atom::Definition d, ld::Atom::Alignment a)
+       : ld::Atom(f._section, d, ld::Atom::combineNever, s, ld::Atom::typeLTOtemporary, ld::Atom::symbolTableIn, false, false, a),
+               _file(f), _name(name), _compiledAtom(NULL)
+{
+}
+
+
+
+
+bool Parser::optimize(const std::vector<ld::Atom*>& allAtoms, std::vector<ld::Atom*>& newAtoms, 
+                                                                                               std::vector<const char*>& additionalUndefines, 
+                                                                                               const std::set<ld::Atom*>& deadAtoms,
+                                                                                               std::vector<ld::Atom*>& newlyDeadAtoms,
+                                                                                               uint32_t nextInputOrdinal, 
+                                                                                               ld::OutFile* writer, ld::Atom* entryPointAtom,
+                                                                                               const std::vector<const char*>& llvmOptions,
+                                                                                               bool allGlobalsAReDeadStripRoots,
+                                                                                               bool verbose, bool saveTemps, 
+                                                                                               const char* outputFilePath,
+                                                                                               bool pie, bool mainExecutable, bool staticExecutable, bool relocatable,
+                                                                                               bool allowTextRelocs, cpu_type_t arch)
+{ 
+       // exit quickly if nothing to do
+       if ( _s_files.size() == 0 ) 
+               return false;
+       
+       // print out LTO version string if -v was used
+       if ( verbose )
+               fprintf(stderr, "%s\n", lto_get_version());
+       
+       // create optimizer and add each Reader
+       lto_code_gen_t generator = ::lto_codegen_create();
+       for (std::vector<File*>::iterator it=_s_files.begin(); it != _s_files.end(); ++it) {
+               if ( ::lto_codegen_add_module(generator, (*it)->module()) )
+                       throwf("lto: could not merge in %s because %s", (*it)->path(), ::lto_get_error_message());
+       }
+
+       // add any -mllvm command line options
+       for (std::vector<const char*>::const_iterator it=llvmOptions.begin(); it != llvmOptions.end(); ++it) {
+               ::lto_codegen_debug_options(generator, *it);
+       }
+
+       // The atom graph uses directed edges (references). Collect all references where 
+       // originating atom is not part of any LTO Reader. This allows optimizer to optimize an 
+       // external (i.e. not originated from same .o file) reference if all originating atoms are also 
+       // defined in llvm bitcode file.
+       CStringSet nonLLVMRefs;
+       CStringToAtom llvmAtoms;
+    bool hasNonllvmAtoms = false;
+       for (std::vector<ld::Atom*>::const_iterator it = allAtoms.begin(); it != allAtoms.end(); ++it) {
+               ld::Atom* atom = *it;
+               // only look at references that come from an atom that is not an llvm atom
+               if ( atom->contentType() != ld::Atom::typeLTOtemporary ) {
+                       // remember if we've seen any atoms not from an llvm reader and not from the writer
+//                     if ( atom->getFile() != writer )
+//                             hasNonllvmAtoms = true;
+                       for (ld::Fixup::iterator fit=atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
+                               if ( fit->binding != ld::Fixup::bindingByNameBound )
+                                       continue;
+                               // and reference an llvm atom
+                               if ( fit->u.target->contentType() == ld::Atom::typeLTOtemporary ) 
+                                       nonLLVMRefs.insert(fit->u.target->name());
+                       }
+               }
+               else {
+                       llvmAtoms[atom->name()] = (Atom*)atom;
+               }
+       }
+       // if entry point is in a llvm bitcode file, it must be preserved by LTO
+       if ( entryPointAtom != NULL ) {
+               if ( entryPointAtom->contentType() == ld::Atom::typeLTOtemporary ) 
+                       nonLLVMRefs.insert(entryPointAtom->name());
+       }
+       
+       // deadAtoms are the atoms that the linker coalesced.  For instance weak or tentative definitions
+       // overriden by another atom.  If any of these deadAtoms are llvm atoms and they were replaced
+       // with a mach-o atom, we need to tell the lto engine to preserve (not optimize away) its dead 
+       // atom so that the linker can replace it with the mach-o one later.
+       CStringToAtom deadllvmAtoms;
+       for (std::set<ld::Atom*>::iterator it = deadAtoms.begin(); it != deadAtoms.end(); ++it) {
+               ld::Atom* atom = *it;
+               if ( atom->contentType() == ld::Atom::typeLTOtemporary ) {
+                       const char* name = atom->name();
+                       ::lto_codegen_add_must_preserve_symbol(generator, name);
+                       deadllvmAtoms[name] = (Atom*)atom;
+               }
+       }
+
+       
+       // tell code generator about symbols that must be preserved
+       for (CStringToAtom::iterator it = llvmAtoms.begin(); it != llvmAtoms.end(); ++it) {
+               const char* name = it->first;
+               Atom* atom = it->second;
+               // Include llvm Symbol in export list if it meets one of following two conditions
+               // 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) ) 
+                       ::lto_codegen_add_must_preserve_symbol(generator, name);
+               else if ( nonLLVMRefs.find(name) != nonLLVMRefs.end() ) 
+                       ::lto_codegen_add_must_preserve_symbol(generator, name);
+       }
+       
+    // special case running ld -r on all bitcode files to produce another bitcode file (instead of mach-o)
+    if ( relocatable && !hasNonllvmAtoms ) {
+               if ( ! ::lto_codegen_write_merged_modules(generator, outputFilePath) ) {
+                       // HACK, no good way to tell linker we are all done, so just quit
+                       exit(0);
+               }
+               warning("could not produce merged bitcode file");
+    }
+    
+       // set code-gen model
+       lto_codegen_model model = LTO_CODEGEN_PIC_MODEL_DYNAMIC;
+       if ( mainExecutable ) {
+               if ( staticExecutable ) {
+                       // darwin x86_64 "static" code model is really dynamic code model
+                       if ( arch == CPU_TYPE_X86_64 )
+                               model = LTO_CODEGEN_PIC_MODEL_DYNAMIC;
+                       else
+                               model = LTO_CODEGEN_PIC_MODEL_STATIC;
+               }
+               else {
+                       if ( pie )
+                               model = LTO_CODEGEN_PIC_MODEL_DYNAMIC;
+                       else
+                               model = LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC;
+               }
+       }
+       else {
+               if ( allowTextRelocs )
+                       model = LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC;
+               else
+                       model = LTO_CODEGEN_PIC_MODEL_DYNAMIC;
+       }
+       if ( ::lto_codegen_set_pic_model(generator, model) )
+               throwf("could not create set codegen model: %s", lto_get_error_message());
+
+    // if requested, save off merged bitcode file
+    if ( saveTemps ) {
+        char tempBitcodePath[MAXPATHLEN];
+        strcpy(tempBitcodePath, outputFilePath);
+        strcat(tempBitcodePath, ".lto.bc");
+        ::lto_codegen_write_merged_modules(generator, tempBitcodePath);
+    }
+
+#if LTO_API_VERSION >= 3
+       // find assembler next to linker
+       char path[PATH_MAX];
+       uint32_t bufSize = PATH_MAX;
+       if ( _NSGetExecutablePath(path, &bufSize) != -1 ) {
+               char* lastSlash = strrchr(path, '/');
+               if ( lastSlash != NULL ) {
+                       strcpy(lastSlash+1, "as");
+                       struct stat statInfo;
+                       if ( stat(path, &statInfo) == 0 )
+                               ::lto_codegen_set_assembler_path(generator, path);
+               }
+       }
+#endif
+       // run code generator
+       size_t machOFileLen;
+       const uint8_t* machOFile = (uint8_t*)::lto_codegen_compile(generator, &machOFileLen);
+       if ( machOFile == NULL ) 
+               throwf("could not do LTO codegen: %s", ::lto_get_error_message());
+       
+    // if requested, save off temp mach-o file
+    if ( saveTemps ) {
+        char tempMachoPath[MAXPATHLEN];
+        strcpy(tempMachoPath, outputFilePath);
+        strcat(tempMachoPath, ".lto.o");
+        int fd = ::open(tempMachoPath, O_CREAT | O_WRONLY | O_TRUNC, 0666);
+               if ( fd != -1) {
+                       ::write(fd, machOFile, machOFileLen);
+                       ::close(fd);
+               }
+               //      save off merged bitcode file
+               char tempOptBitcodePath[MAXPATHLEN];
+        strcpy(tempOptBitcodePath, outputFilePath);
+        strcat(tempOptBitcodePath, ".lto.opt.bc");
+        ::lto_codegen_write_merged_modules(generator, tempOptBitcodePath);
+       }
+
+       // parse generated mach-o file into a MachOReader
+       ld::File* machoFile = parseMachOFile(machOFile, machOFileLen, nextInputOrdinal, arch);
+       
+       // sync generated mach-o atoms with existing atoms ld knows about
+       AtomSyncer syncer(additionalUndefines,newAtoms,llvmAtoms,deadllvmAtoms);
+       machoFile->forEachAtom(syncer);
+                       
+       // Remove InternalAtoms from ld
+       for (std::vector<File*>::iterator it=_s_files.begin(); it != _s_files.end(); ++it) {
+               newlyDeadAtoms.push_back(&((*it)->internalAtom()));
+       }
+       // Remove Atoms from ld if code generator optimized them away
+       for (CStringToAtom::iterator li = llvmAtoms.begin(), le = llvmAtoms.end(); li != le; ++li) {
+               // check if setRealAtom() called on this Atom
+               if ( li->second->compiledAtom() == NULL )
+                       newlyDeadAtoms.push_back(li->second);
+       }
+       
+       return true;
+}
+
+
+void Parser::AtomSyncer::doAtom(ld::Atom& machoAtom)
+{
+       // update proxy atoms to point to real atoms and find new atoms
+       const char* name = machoAtom.name();
+       if ( machoAtom.scope() >= ld::Atom::scopeLinkageUnit ) {
+               CStringToAtom::iterator pos = llvmAtoms.find(name);
+               if ( pos != llvmAtoms.end() ) {
+                       // turn Atom into a proxy for this mach-o atom
+                       pos->second->setCompiledAtom(machoAtom);
+               }
+               else {
+                       // an atom of this name was not in the allAtoms list the linker gave us
+                       if ( deadllvmAtoms.find(name) != deadllvmAtoms.end() ) {
+                               // this corresponding to an atom that the linker coalesced away.  
+                               // Don't pass it back as a new atom
+                       }
+                       else
+                       {
+                               // this is something new that lto conjured up, tell ld its new
+                               newAtoms.push_back(&machoAtom);
+                       }
+               }
+       }
+       else {
+               // ld only knew about non-satic atoms, so this one must be new
+               newAtoms.push_back(&machoAtom);
+       }
+       
+       // adjust fixups to go through proxy atoms
+       for (ld::Fixup::iterator fit=machoAtom.fixupsBegin(); fit != machoAtom.fixupsEnd(); ++fit) {
+               switch ( fit->binding ) {
+                       case ld::Fixup::bindingNone:
+                               break;
+                       case ld::Fixup::bindingByNameUnbound:
+                               // don't know if this target has been seen by linker before or if it is new
+                               // be conservitive and tell linker it is new
+                               additionalUndefines.push_back(fit->u.name);
+                               break;
+                       case ld::Fixup::bindingByNameBound:
+                               break;
+                       case ld::Fixup::bindingDirectlyBound:
+                               // If mach-o atom is referencing another mach-o atom then 
+                               // reference is not going through Atom proxy. Fix it here to ensure that all
+                               // llvm symbol references always go through Atom proxy.
+                               break;
+                       case ld::Fixup::bindingByContentBound:
+                               break;
+               }
+       }
+
+}
+       
+
+
+}; // namespace lto
+
+
+#endif
+
diff --git a/src/ld/parsers/archive_file.cpp b/src/ld/parsers/archive_file.cpp
new file mode 100644 (file)
index 0000000..8c866cd
--- /dev/null
@@ -0,0 +1,522 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <stdint.h>
+#include <math.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <mach-o/ranlib.h>
+#include <ar.h>
+
+#include <vector>
+#include <set>
+#include <algorithm>
+#include <ext/hash_map>
+
+#include "MachOFileAbstraction.hpp"
+#include "Architectures.hpp"
+
+#include "macho_relocatable_file.h"
+#include "lto_file.h"
+#include "archive_file.h"
+
+
+namespace archive {
+
+typedef const struct ranlib* ConstRanLibPtr;
+
+// forward reference
+template <typename A> class File;
+
+
+template <typename A>
+class Parser 
+{
+public:
+       typedef typename A::P                                   P;
+
+       static bool                                                                             validFile(const uint8_t* fileContent, uint64_t fileLength, 
+                                                                                                                               const mach_o::relocatable::ParserOptions& opts) {
+                                                                                                               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) {
+                                                                                                                        return new File<A>(fileContent, fileLength, path, mTime,
+                                                                                                                                                       ordinal, opts);
+                                                                                                               }
+
+};
+
+template <typename A>
+class File : public ld::File
+{
+public:
+       static bool                                                                             validFile(const uint8_t* fileContent, uint64_t fileLength,
+                                                                                                                               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);
+       virtual                                                                                 ~File() {}
+
+       // overrides of ld::File
+       virtual bool                                                                            forEachAtom(ld::File::AtomHandler&) const;
+       virtual bool                                                                            justInTimeforEachAtom(const char* name, ld::File::AtomHandler&) const;
+       virtual uint32_t                                                                        subFileCount() const  { return _archiveFilelength/sizeof(ar_hdr); }
+       
+private:
+       static bool                                                                             validMachOFile(const uint8_t* fileContent, uint64_t fileLength, 
+                                                                                                                                       const mach_o::relocatable::ParserOptions& opts);
+       static bool                                                                             validLTOFile(const uint8_t* fileContent, uint64_t fileLength, 
+                                                                                                                                       const mach_o::relocatable::ParserOptions& opts);
+       static cpu_type_t                                                               architecture();
+
+
+       class Entry : ar_hdr
+       {
+       public:
+               const char*                     name() const;
+               time_t                          modificationTime() const;
+               const uint8_t*          content() const;
+               uint32_t                        contentSize() const;
+               const Entry*            next() const;
+       private:
+               bool                            hasLongName() const;
+               unsigned int            getLongNameSpace() const;
+
+       };
+
+       class CStringEquals
+       {
+       public:
+               bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+       };
+       typedef __gnu_cxx::hash_map<const char*, const struct ranlib*, __gnu_cxx::hash<const char*>, CStringEquals> NameToEntryMap;
+
+       typedef typename A::P                                                   P;
+       typedef typename A::P::E                                                E;
+
+       const struct ranlib*                                                    ranlibHashSearch(const char* name) const;
+       ld::relocatable::File*                                                  makeObjectFileForMember(const Entry* member) const;
+       bool                                                                                    memberHasObjCCategories(const Entry* member) const;
+       void                                                                                    dumpTableOfContents();
+       void                                                                                    buildHashTable();
+
+       const uint8_t*                                                                  _archiveFileContent;
+       uint64_t                                                                                _archiveFilelength;
+       const struct ranlib*                                                    _tableOfContents;
+       uint32_t                                                                                _tableOfContentCount;
+       const char*                                                                             _tableOfContentStrings;
+       mutable std::vector<ld::relocatable::File*>             _instantiatedFiles;
+       mutable std::set<const class Entry*>                    _instantiatedEntries;
+       NameToEntryMap                                                                  _hashTable;
+       const bool                                                                              _forceLoadAll;
+       const bool                                                                              _forceLoadObjC;
+       const bool                                                                              _forceLoadThis;
+       const bool                                                                              _verboseLoad;
+       const bool                                                                              _logAllFiles;
+       const mach_o::relocatable::ParserOptions                _objOpts;
+};
+
+
+template <typename A>
+bool File<A>::Entry::hasLongName() const
+{
+       return ( strncmp(this->ar_name, AR_EFMT1, strlen(AR_EFMT1)) == 0 );
+}
+
+template <typename A>
+unsigned int File<A>::Entry::getLongNameSpace() const
+{
+       char* endptr;
+       long result = strtol(&this->ar_name[strlen(AR_EFMT1)], &endptr, 10);
+       return result;
+}
+
+template <typename A>
+const char* File<A>::Entry::name() 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;
+       }
+       else {
+               static char shortName[20];
+               strncpy(shortName, this->ar_name, 16);
+               shortName[16] = '\0';
+               char* space = strchr(shortName, ' ');
+               if ( space != NULL )
+                       *space = '\0';
+               return shortName;
+       }
+}
+
+template <typename A>
+time_t File<A>::Entry::modificationTime() const
+{
+       char temp[14];
+       strncpy(temp, this->ar_date, 12);
+       temp[12] = '\0';
+       char* endptr;
+       return (time_t)strtol(temp, &endptr, 10);
+}
+
+
+template <typename A>
+const uint8_t* File<A>::Entry::content() const
+{
+       if ( this->hasLongName() )
+               return ((uint8_t*)this) + sizeof(ar_hdr) + this->getLongNameSpace();
+       else
+               return ((uint8_t*)this) + sizeof(ar_hdr);
+}
+
+
+template <typename A>
+uint32_t File<A>::Entry::contentSize() const
+{
+       char temp[12];
+       strncpy(temp, this->ar_size, 10);
+       temp[10] = '\0';
+       char* endptr;
+       long size = strtol(temp, &endptr, 10);
+       // long name is included in ar_size
+       if ( this->hasLongName() )
+               size -= this->getLongNameSpace();
+       return size;
+}
+
+
+template <typename A>
+const class File<A>::Entry* File<A>::Entry::next() const
+{
+       const uint8_t* p = this->content() + contentSize();
+       p = (const uint8_t*)(((uintptr_t)p+3) & (-4));  // 4-byte align
+       return (class File<A>::Entry*)p;
+}
+
+
+template <> cpu_type_t File<ppc>::architecture()    { return CPU_TYPE_POWERPC; }
+template <> cpu_type_t File<ppc64>::architecture()  { return CPU_TYPE_POWERPC64; }
+template <> cpu_type_t File<x86>::architecture()    { return CPU_TYPE_I386; }
+template <> cpu_type_t File<x86_64>::architecture() { return CPU_TYPE_X86_64; }
+template <> cpu_type_t File<arm>::architecture()    { return CPU_TYPE_ARM; }
+
+
+template <typename A>
+bool File<A>::validMachOFile(const uint8_t* fileContent, uint64_t fileLength, const mach_o::relocatable::ParserOptions& opts)
+{      
+       return mach_o::relocatable::isObjectFile(fileContent, fileLength, opts);
+}
+
+template <typename A>
+bool File<A>::validLTOFile(const uint8_t* fileContent, uint64_t fileLength, const mach_o::relocatable::ParserOptions& opts)
+{
+       return lto::isObjectFile(fileContent, fileLength, opts.architecture, opts.subType);
+}
+
+
+
+template <typename A>
+bool File<A>::validFile(const uint8_t* fileContent, uint64_t fileLength, const mach_o::relocatable::ParserOptions& opts)
+{
+       // must have valid archive header
+       if ( strncmp((const char*)fileContent, "!<arch>\n", 8) != 0 )
+               return false;
+               
+       // peak at first .o file and verify it is correct architecture
+       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();
+               // skip option table-of-content member
+               if ( (p==start) && ((strcmp(memberName, SYMDEF_SORTED) == 0) || (strcmp(memberName, SYMDEF) == 0)) )
+                       continue;
+               // archive is valid if first .o file is valid
+               return (validMachOFile(p->content(), p->contentSize(), opts) || validLTOFile(p->content(), p->contentSize(), opts));
+       }       
+       // empty archive
+       return true;
+}
+
+
+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(strdup(pth), modTime, ord),
+       _archiveFileContent(fileContent), _archiveFilelength(fileLength), 
+       _tableOfContents(NULL), _tableOfContentCount(0), _tableOfContentStrings(NULL), 
+       _forceLoadAll(opts.forceLoadAll), _forceLoadObjC(opts.forceLoadObjC), 
+       _forceLoadThis(opts.forceLoadThisArchive), _verboseLoad(opts.verboseLoad), 
+       _logAllFiles(opts.logAllFiles), _objOpts(opts.objOpts)
+{
+       if ( strncmp((const char*)fileContent, "!<arch>\n", 8) != 0 )
+               throw "not an archive";
+
+       if ( !_forceLoadAll ) {
+               const Entry* const firstMember = (Entry*)&_archiveFileContent[8];
+               if ( (strcmp(firstMember->name(), SYMDEF_SORTED) == 0) || (strcmp(firstMember->name(), SYMDEF) == 0) ) {
+                       const uint8_t* contents = firstMember->content();
+                       uint32_t ranlibArrayLen = E::get32(*((uint32_t*)contents));
+                       _tableOfContents = (const struct ranlib*)&contents[4];
+                       _tableOfContentCount = ranlibArrayLen / sizeof(struct ranlib);
+                       _tableOfContentStrings = (const char*)&contents[ranlibArrayLen+8];
+                       if ( ((uint8_t*)(&_tableOfContents[_tableOfContentCount]) > &fileContent[fileLength])
+                               || ((uint8_t*)_tableOfContentStrings > &fileContent[fileLength]) )
+                               throw "malformed archive, perhaps wrong architecture";
+                       this->buildHashTable();
+               }
+               else
+                       throw "archive has no table of contents";
+       }
+}
+
+template <>
+bool File<x86>::memberHasObjCCategories(const Entry* member) const
+{
+       // i386 uses ObjC1 ABI which has .objc_category* global symbols
+       return false;
+}
+
+template <>
+bool File<ppc>::memberHasObjCCategories(const Entry* member) const
+{
+       // ppc uses ObjC1 ABI which has .objc_category* global symbols
+       return false;
+}
+
+
+template <typename A>
+bool File<A>::memberHasObjCCategories(const Entry* member) const
+{
+       // x86_64 and ARM use ObjC2 which has no global symbol for categories
+       return mach_o::relocatable::hasObjC2Categories(member->content());
+}
+
+
+template <typename A>
+ld::relocatable::File* File<A>::makeObjectFileForMember(const Entry* member) const
+{
+       const char* memberName = member->name();
+       char memberPath[strlen(this->path()) + strlen(memberName)+4];
+       strcpy(memberPath, this->path());
+       strcat(memberPath, "(");
+       strcat(memberPath, memberName);
+       strcat(memberPath, ")");
+       //fprintf(stderr, "using %s from %s\n", memberName, this->path());
+       try {
+               // range check
+               if ( member > (Entry*)(_archiveFileContent+_archiveFilelength) )
+                       throwf("corrupt archive, member starts past end of file");                                                                              
+               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::relocatable::File* result = mach_o::relocatable::parse(member->content(), member->contentSize(), 
+                                                                                                                                       mPath, member->modificationTime(), 
+                                                                                                                                       this->ordinal() + memberIndex, _objOpts);
+               if ( result != NULL )
+                       return result;
+               // see if member is llvm bitcode file
+               result = lto::parse(member->content(), member->contentSize(), 
+                                                               mPath, member->modificationTime(), this->ordinal() + memberIndex, 
+                                                               _objOpts.architecture, _objOpts.subType, _logAllFiles);
+               if ( result != NULL )
+                       return result;
+                       
+               throwf("archive member '%s' with length %d is not mach-o or llvm bitcode", memberName, member->contentSize());
+       }
+       catch (const char* msg) {
+               throwf("in %s, %s", memberPath, msg);
+       }
+}
+
+
+template <typename A>
+bool File<A>::forEachAtom(ld::File::AtomHandler& handler) const
+{
+       bool didSome = false;
+       if ( _forceLoadAll || _forceLoadThis ) {
+               // call handler on all .o files in this archive
+               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();
+                       if ( (p==start) && ((strcmp(memberName, SYMDEF_SORTED) == 0) || (strcmp(memberName, SYMDEF) == 0)) )
+                               continue;
+                       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);
+                       }
+                       ld::relocatable::File* file = this->makeObjectFileForMember(p);
+                       didSome |= file->forEachAtom(handler);
+               }
+       }
+       else if ( _forceLoadObjC ) {
+               // call handler on all .o files in this archive containing objc classes
+               for(typename NameToEntryMap::const_iterator it = _hashTable.begin(); it != _hashTable.end(); ++it) {
+                       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)];
+                               if ( _instantiatedEntries.count(member) == 0 ) {
+                                       if ( _verboseLoad )
+                                               printf("-ObjC forced load of %s(%s)\n", this->path(), member->name());
+                                       // only return these atoms once
+                                       _instantiatedEntries.insert(member);
+                                       ld::relocatable::File* file = this->makeObjectFileForMember(member);
+                                       didSome |= file->forEachAtom(handler);
+                                       _instantiatedFiles.push_back(file);
+                               }
+                       }
+               }
+               // 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());
+                               if ( this->memberHasObjCCategories(member) ) {
+                                       if ( _verboseLoad )
+                                               printf("-ObjC forced load of %s(%s)\n", this->path(), member->name());
+                                       // only return these atoms once
+                                       _instantiatedEntries.insert(member);
+                                       ld::relocatable::File* file = this->makeObjectFileForMember(member);
+                                       didSome |= file->forEachAtom(handler);
+                                       _instantiatedFiles.push_back(file);
+                               }
+                       }
+               }
+       }
+       return didSome;
+}
+
+template <typename A>
+bool File<A>::justInTimeforEachAtom(const char* name, ld::File::AtomHandler& handler) const
+{
+       // in force load case, all members already loaded
+       if ( _forceLoadAll || _forceLoadThis ) 
+               return false;
+       
+       // do a hash search of table of contents looking for requested symbol
+       const struct ranlib* result = ranlibHashSearch(name);
+       if ( result != NULL ) {
+               const Entry* member = (Entry*)&_archiveFileContent[E::get32(result->ran_off)];
+               // only call handler for each member once
+               if ( _instantiatedEntries.count(member) == 0 ) {
+                       _instantiatedEntries.insert(member);
+                       if ( _verboseLoad ) 
+                               printf("%s forced load of %s(%s)\n", name, this->path(), member->name());
+                       ld::relocatable::File* file = this->makeObjectFileForMember(member);
+                       _instantiatedFiles.push_back(file);
+                       return file->forEachAtom(handler);
+               }
+       }
+       //fprintf(stderr, "%s NOT found in archive %s\n", name, this->path());
+       return false;
+}
+
+
+typedef const struct ranlib* ConstRanLibPtr;
+
+template <typename A>
+ConstRanLibPtr  File<A>::ranlibHashSearch(const char* name) const
+{
+       typename NameToEntryMap::const_iterator pos = _hashTable.find(name);
+       if ( pos != _hashTable.end() )
+               return pos->second;
+       else
+               return NULL;
+}
+
+template <typename A>
+void File<A>::buildHashTable()
+{
+       // walk through list backwards, adding/overwriting entries
+       // this assures that with duplicates those earliest in the list will be found
+       for (int i = _tableOfContentCount-1; i >= 0; --i) {
+               const struct ranlib* entry = &_tableOfContents[i];
+               const char* entryName = &_tableOfContentStrings[E::get32(entry->ran_un.ran_strx)];
+               if ( E::get32(entry->ran_off) > _archiveFilelength ) {
+                       throwf("malformed archive TOC entry for %s, offset %d is beyond end of file %lld\n",
+                               entryName, entry->ran_off, _archiveFilelength);
+               }
+               
+               //const Entry* member = (Entry*)&_archiveFileContent[E::get32(entry->ran_off)];
+               //fprintf(stderr, "adding hash %d, %s -> %p\n", i, entryName, entry);
+               _hashTable[entryName] = entry;
+       }
+}
+
+template <typename A>
+void File<A>::dumpTableOfContents()
+{
+       for (unsigned int i=0; i < _tableOfContentCount; ++i) {
+               const struct ranlib* e = &_tableOfContents[i];
+               printf("%s in %s\n", &_tableOfContentStrings[E::get32(e->ran_un.ran_strx)], ((Entry*)&_archiveFileContent[E::get32(e->ran_off)])->name());
+       }
+}
+
+
+//
+// main function used by linker to instantiate archive files
+//
+ld::File* parse(const uint8_t* fileContent, uint64_t fileLength, 
+                               const char* path, time_t modTime, uint32_t ordinal, const ParserOptions& opts)
+{
+       switch ( opts.objOpts.architecture ) {
+               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;
+               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;
+               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;
+               case CPU_TYPE_POWERPC:
+                       if ( archive::Parser<ppc>::validFile(fileContent, fileLength, opts.objOpts) )
+                               return archive::Parser<ppc>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
+                       break;
+               case CPU_TYPE_POWERPC64:
+                       if ( archive::Parser<ppc64>::validFile(fileContent, fileLength, opts.objOpts) )
+                               return archive::Parser<ppc64>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
+                       break;
+       }
+       return NULL;
+}
+
+
+
+}; // namespace archive
+
+
diff --git a/src/ld/parsers/archive_file.h b/src/ld/parsers/archive_file.h
new file mode 100644 (file)
index 0000000..4dcbc8b
--- /dev/null
@@ -0,0 +1,48 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __ARCHIVE_FILE_H__
+#define __ARCHIVE_FILE_H__
+
+#include "ld.hpp"
+#include "macho_relocatable_file.h"
+
+namespace archive {
+
+struct ParserOptions {
+       mach_o::relocatable::ParserOptions      objOpts;
+       bool                                                            forceLoadThisArchive;
+       bool                                                            forceLoadAll;
+       bool                                                            forceLoadObjC;
+       bool                                                            verboseLoad;
+       bool                                                            logAllFiles;
+};
+
+extern ld::File* parse(const uint8_t* fileContent, uint64_t fileLength, 
+                                               const char* path, time_t modTime, uint32_t ordinal, const ParserOptions& opts);
+
+} // namespace archive
+
+
+#endif // __ARCHIVE_FILE_H__
diff --git a/src/ld/parsers/lto_file.cpp b/src/ld/parsers/lto_file.cpp
new file mode 100644 (file)
index 0000000..6221c90
--- /dev/null
@@ -0,0 +1,870 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2006-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@
+ */
+
+#ifndef __LTO_READER_H__
+#define __LTO_READER_H__
+
+#include <stdlib.h>
+#include <sys/param.h>
+#include <sys/fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <mach-o/dyld.h>
+#include <vector>
+#include <ext/hash_set>
+#include <ext/hash_map>
+
+#include "MachOFileAbstraction.hpp"
+#include "Architectures.hpp"
+#include "ld.hpp"
+#include "macho_relocatable_file.h"
+#include "lto_file.h"
+
+#include "llvm-c/lto.h"
+
+
+namespace lto {
+         
+
+//
+// ld64 only tracks non-internal symbols from an llvm bitcode file.  
+// We model this by having an InternalAtom which represent all internal functions and data.
+// All non-interal symbols from a bitcode file are represented by an Atom
+// and each Atom has a reference to the InternalAtom.  The InternalAtom
+// also has references to each symbol external to the bitcode file. 
+//
+class InternalAtom : public ld::Atom
+{
+public:
+                                                                                               InternalAtom(class File& f);
+       // overrides of ld::Atom
+       virtual ld::File*                                                       file() const            { return &_file; }
+       virtual bool                                                            translationUnitSource(const char** dir, const char** nm) const
+                                                                                                                                       { return false; }
+       virtual const char*                                                     name() const            { return "import-atom"; }
+       virtual uint64_t                                                        size() const            { return 0; }
+       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 &_undefs[0]; }
+       virtual ld::Fixup::iterator                                     fixupsEnd()     const   { return &_undefs[_undefs.size()]; }
+
+       // for adding references to symbols outside bitcode file
+       void                                                                            addReference(const char* nm)
+                                                                                                                                       { _undefs.push_back(ld::Fixup(0, ld::Fixup::k1of1, 
+                                                                                                                                                               ld::Fixup::kindNone, false, nm)); }
+private:
+
+       ld::File&                                                                       _file;
+       mutable std::vector<ld::Fixup>                          _undefs;
+};
+
+
+//
+// LLVM bitcode file 
+//
+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);
+       virtual                                                                 ~File();
+
+       // overrides of ld::File
+       virtual bool                                                                            forEachAtom(ld::File::AtomHandler&) const;
+       virtual bool                                                                            justInTimeforEachAtom(const char* name, ld::File::AtomHandler&) const 
+                                                                                                                                                                       { return false; }
+       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 
+                                                                                                                                                                       { return _debugInfoModTime; }
+       virtual const std::vector<ld::relocatable::File::Stab>* stabs() const                   { return NULL; }
+       virtual bool                                                                            canScatterAtoms() const         { return true; }
+
+       lto_module_t                                                                            module()                                        { return _module; }
+       class InternalAtom&                                                                     internalAtom()                          { return _internalAtom; }
+       void                                                                                            setDebugInfo(ld::relocatable::File::DebugInfoKind k,
+                                                                                                                                       const char* pth, time_t modTime, uint32_t subtype)
+                                                                                                                                                                       {       _debugInfo = k; 
+                                                                                                                                                                               _debugInfoPath = pth; 
+                                                                                                                                                                               _debugInfoModTime = modTime; 
+                                                                                                                                                                               _cpuSubType = subtype;}
+
+private:
+       friend class Atom;
+       friend class InternalAtom;
+       friend class Parser;
+       
+       cpu_type_t                                                              _architecture;
+       class InternalAtom                                              _internalAtom;
+       class Atom*                                                             _atomArray;
+       uint32_t                                                                _atomArrayCount;
+       lto_module_t                                                    _module;
+       const char*                                                             _debugInfoPath;
+       time_t                                                                  _debugInfoModTime;
+       ld::Section                                                             _section;
+       ld::Fixup                                                               _fixupToInternal;
+       ld::relocatable::File::DebugInfoKind    _debugInfo; 
+       uint32_t                                                                _cpuSubType;
+};
+
+//
+// Atom acts as a proxy Atom for the symbols that are exported by LLVM bitcode file. Initially,
+// Reader creates Atoms to allow linker proceed with usual symbol resolution phase. After
+// optimization is performed, real Atoms are created for these symobls. However these real Atoms
+// are not inserted into global symbol table. Atom holds real Atom and forwards appropriate
+// methods to real atom.
+//
+class Atom : public ld::Atom
+{
+public:
+                                                                               Atom(File& f, const char* name, ld::Atom::Scope s, 
+                                                                                               ld::Atom::Definition d, ld::Atom::Combine c, ld::Atom::Alignment a);
+
+       // overrides of ld::Atom
+       virtual ld::File*                                       file() const            { return &_file; }
+       virtual bool                                            translationUnitSource(const char** dir, const char** nm) const
+                                                                                                                       { return (_compiledAtom ? _compiledAtom->translationUnitSource(dir, nm) : false); }
+       virtual const char*                                     name() const            { return _name; }
+       virtual uint64_t                                        size() const            { return (_compiledAtom ? _compiledAtom->size() : 0); }
+       virtual uint64_t                                        objectAddress() const { return (_compiledAtom ? _compiledAtom->objectAddress() : 0); }
+       virtual void                                            copyRawContent(uint8_t buffer[]) const 
+                                                                                                                       { if (_compiledAtom) _compiledAtom->copyRawContent(buffer); }
+       virtual const uint8_t*                          rawContentPointer() const 
+                                                                                                                       { return (_compiledAtom ? _compiledAtom->rawContentPointer() : NULL);  }
+       virtual unsigned long                           contentHash(const class ld::IndirectBindingTable& ibt) const 
+                                                                                                                       { return (_compiledAtom ? _compiledAtom->contentHash(ibt) : 0);  }
+       virtual bool                                            canCoalesceWith(const ld::Atom& rhs, const class ld::IndirectBindingTable& ibt) const 
+                                                                                                                       { return (_compiledAtom ? _compiledAtom->canCoalesceWith(rhs,ibt) : false); }
+       virtual ld::Fixup::iterator                             fixupsBegin() const     
+                                                                                                                       { return (_compiledAtom ? _compiledAtom->fixupsBegin() : (ld::Fixup*)&_file._fixupToInternal); }
+       virtual ld::Fixup::iterator                             fixupsEnd() const       
+                                                                                                                       { return (_compiledAtom ? _compiledAtom->fixupsEnd() : &((ld::Fixup*)&_file._fixupToInternal)[1]); }
+       virtual ld::Atom::UnwindInfo::iterator  beginUnwind() const 
+                                                                                                                       { return (_compiledAtom ? _compiledAtom->beginUnwind() : NULL); }
+       virtual ld::Atom::UnwindInfo::iterator  endUnwind() const       
+                                                                                                                       { return (_compiledAtom ? _compiledAtom->endUnwind() : NULL); }
+       virtual ld::Atom::LineInfo::iterator    beginLineInfo() const 
+                                                                                                                       { return (_compiledAtom ? _compiledAtom->beginLineInfo() : NULL); }
+       virtual ld::Atom::LineInfo::iterator    endLineInfo() const 
+                                                                                                                       { return (_compiledAtom ? _compiledAtom->endLineInfo() : NULL); }
+                                                                                                                       
+       const ld::Atom*                                         compiledAtom()          { return _compiledAtom; }
+       void                                                            setCompiledAtom(const ld::Atom& atom);
+
+private:
+
+       File&                                                           _file;
+       const char*                                                     _name;
+       const ld::Atom*                                         _compiledAtom;
+};
+
+                                                                                       
+
+
+
+
+
+class Parser 
+{
+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);
+       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, 
+                                                                                               std::vector<const char*>&                       additionalUndefines);
+
+       static const char*                      ltoVersion()    { return ::lto_get_version(); }
+
+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);
+
+       class CStringEquals
+       {
+       public:
+               bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+       };
+       typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals>  CStringSet;
+       typedef __gnu_cxx::hash_map<const char*, Atom*, __gnu_cxx::hash<const char*>, CStringEquals> CStringToAtom;
+       
+       class AtomSyncer : public ld::File::AtomHandler {
+       public:
+                                                       AtomSyncer(std::vector<const char*>& a, std::vector<const ld::Atom*>&na,
+                                                                               CStringToAtom la, CStringToAtom dla, const OptimizeOptions& options) :
+                                                                               _options(options), _additionalUndefines(a), _newAtoms(na), _llvmAtoms(la), _deadllvmAtoms(dla) { }
+               virtual void            doAtom(const class ld::Atom&);
+               virtual void            doFile(const class ld::File&) { }
+               
+               const OptimizeOptions&                  _options;
+               std::vector<const char*>&               _additionalUndefines;
+               std::vector<const ld::Atom*>&   _newAtoms;
+               CStringToAtom                                   _llvmAtoms;
+               CStringToAtom                                   _deadllvmAtoms;
+       };
+
+       static std::vector<File*>               _s_files;
+};
+
+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:
+                       switch ( subarch ) {
+                               case CPU_SUBTYPE_ARM_V6:
+                                       return ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, "armv6-");
+                               case CPU_SUBTYPE_ARM_V7:
+                                       return ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, "thumbv7-");
+                       }
+                       break;
+               case CPU_TYPE_POWERPC:
+                       return ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, "powerpc-");
+       }
+       return false;
+}
+
+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_POWERPC:
+                               return "ppc";
+                       case CPU_TYPE_I386:
+                               return "i386";
+                       case CPU_TYPE_X86_64:
+                               return "x86_64";
+                       case CPU_TYPE_ARM:
+                               if ( ::lto_module_is_object_file_in_memory_for_target(p, fileLength, "armv6-") )
+                                       return "armv6";
+                               if ( ::lto_module_is_object_file_in_memory_for_target(p, fileLength, "thumbv7-") )
+                                       return "armv7";
+                               return "arm";
+               }
+               return "unknown bitcode architecture";
+       }
+       return NULL;
+}
+
+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) 
+{
+       File* f = new File(path, modTime, fileContent, fileLength, ordinal, architecture);
+       _s_files.push_back(f);
+       if ( logAllFiles ) 
+               printf("%s\n", path);
+       return f;
+}
+
+
+ld::relocatable::File* Parser::parseMachOFile(const uint8_t* p, size_t len, uint32_t nextInputOrdinal, const OptimizeOptions& options) 
+{
+       mach_o::relocatable::ParserOptions objOpts;
+       objOpts.architecture            = options.arch;
+       objOpts.objSubtypeMustMatch = false; 
+       objOpts.logAllFiles                     = false;
+       objOpts.convertUnwindInfo       = true;
+       objOpts.subType                         = 0;
+       
+       // mach-o parsing is done in-memory, but need path for debug notes
+       const char* path = "/tmp/lto.o";
+       time_t modTime = 0;
+       if ( options.tmpObjectFilePath != NULL ) {
+               path = options.tmpObjectFilePath;
+               struct stat statBuffer;
+               if ( stat(options.tmpObjectFilePath, &statBuffer) == 0 )
+                       modTime = statBuffer.st_mtime;
+       }
+       
+       ld::relocatable::File* result = mach_o::relocatable::parse(p, len, path, modTime, nextInputOrdinal, objOpts);
+       if ( result != NULL )
+               return result;
+       throw "LLVM LTO, file is not of required architecture";
+}
+
+
+
+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), 
+       _atomArray(NULL), _atomArrayCount(0), _module(NULL), _debugInfoPath(pth), 
+       _section("__TEXT_", "__tmp_lto", ld::Section::typeTempLTO),
+       _fixupToInternal(0, ld::Fixup::k1of1, ld::Fixup::kindNone, &_internalAtom),
+       _debugInfo(ld::relocatable::File::kDebugInfoNone), _cpuSubType(0)
+{
+       const bool log = false;
+       
+       // create llvm module
+       _module = ::lto_module_create_from_memory(content, contentLength);
+    if ( _module == NULL )
+               throwf("could not parse object file %s: %s", pth, lto_get_error_message());
+
+       if ( log ) fprintf(stderr, "bitcode file: %s\n", pth);
+       
+       // create atom for each global symbol in module
+       uint32_t count = ::lto_module_get_num_symbols(_module);
+       _atomArray = (Atom*)malloc(sizeof(Atom)*count);
+       for (uint32_t i=0; i < count; ++i) {
+               const char* name = ::lto_module_get_symbol_name(_module, i);
+               lto_symbol_attributes attr = lto_module_get_symbol_attribute(_module, i);
+
+               // <rdar://problem/6378110> LTO doesn't like dtrace symbols
+               // ignore dtrace static probes for now
+               // later when codegen is done and a mach-o file is produces the probes will be processed
+               if ( (strncmp(name, "___dtrace_probe$", 16) == 0) || (strncmp(name, "___dtrace_isenabled$", 20) == 0) )
+                       continue;
+                               
+               ld::Atom::Definition def;
+               ld::Atom::Combine combine = ld::Atom::combineNever;
+               switch ( attr & LTO_SYMBOL_DEFINITION_MASK ) {
+                       case LTO_SYMBOL_DEFINITION_REGULAR:
+                               def = ld::Atom::definitionRegular;
+                               break;
+                       case LTO_SYMBOL_DEFINITION_TENTATIVE:
+                               def = ld::Atom::definitionTentative;
+                               break;
+                       case LTO_SYMBOL_DEFINITION_WEAK:
+                               def = ld::Atom::definitionRegular;
+                               combine = ld::Atom::combineByName;
+                               break;
+                       case LTO_SYMBOL_DEFINITION_UNDEFINED:
+                       case LTO_SYMBOL_DEFINITION_WEAKUNDEF:
+                               def = ld::Atom::definitionProxy;
+                               break;
+                       default:
+                               throwf("unknown definition kind for symbol %s in bitcode file %s", name, pth);
+               }
+
+               // make LLVM atoms for definitions and a reference for undefines
+               if ( def != ld::Atom::definitionProxy ) {
+                       ld::Atom::Scope scope;
+                       switch ( attr & LTO_SYMBOL_SCOPE_MASK) {
+                               case LTO_SYMBOL_SCOPE_INTERNAL:
+                                       scope = ld::Atom::scopeTranslationUnit;
+                                       break;
+                               case LTO_SYMBOL_SCOPE_HIDDEN:
+                                       scope = ld::Atom::scopeLinkageUnit;
+                                       break;
+                               case LTO_SYMBOL_SCOPE_DEFAULT:
+                                       scope = ld::Atom::scopeGlobal;
+                                       break;
+                               default:
+                                       throwf("unknown scope for symbol %s in bitcode file %s", name, pth);
+                       }
+                       // only make atoms for non-internal symbols 
+                       if ( scope == ld::Atom::scopeTranslationUnit )
+                               continue;
+                       uint8_t alignment = (attr & LTO_SYMBOL_ALIGNMENT_MASK);
+                       // make Atom using placement new operator
+                       new (&_atomArray[_atomArrayCount++]) Atom(*this, name, scope, def, combine, alignment);
+                       if ( scope == ld::Atom::scopeLinkageUnit )
+                               _internalAtom.addReference(name);
+                       if ( log ) fprintf(stderr, "\t0x%08X %s\n", attr, name);
+               }
+               else {
+                       // add to list of external references
+                       _internalAtom.addReference(name);
+                       if ( log ) fprintf(stderr, "\t%s (undefined)\n", name);
+               }
+       }
+}
+
+File::~File()
+{
+       if ( _module != NULL )
+               ::lto_module_dispose(_module);
+}
+
+bool File::forEachAtom(ld::File::AtomHandler& handler) const
+{
+       handler.doAtom(_internalAtom);
+       for(uint32_t i=0; i < _atomArrayCount; ++i) {
+               handler.doAtom(_atomArray[i]);
+       }
+       return true;
+}
+
+InternalAtom::InternalAtom(File& f)
+       : ld::Atom(f._section, ld::Atom::definitionRegular, ld::Atom::combineNever, ld::Atom::scopeTranslationUnit, 
+                               ld::Atom::typeLTOtemporary, ld::Atom::symbolTableNotIn, true, false, false, ld::Atom::Alignment(0)),
+               _file(f)
+{
+}
+
+Atom::Atom(File& f, const char* nm, ld::Atom::Scope s, ld::Atom::Definition d, ld::Atom::Combine c, ld::Atom::Alignment a)
+       : ld::Atom(f._section, d, c, s, ld::Atom::typeLTOtemporary, 
+                               ld::Atom::symbolTableIn, false, false, false, a),
+               _file(f), _name(nm), _compiledAtom(NULL)
+{
+}
+
+void Atom::setCompiledAtom(const ld::Atom& atom)
+{
+       // set delegate so virtual methods go to it
+       _compiledAtom = &atom;
+       
+       //fprintf(stderr, "setting lto atom %p to delegate to mach-o atom %p (%s)\n", this, &atom, atom.name());
+       
+       // update fields in ld::Atom to match newly constructed mach-o atom
+       (const_cast<Atom*>(this))->setAttributesFromAtom(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, 
+                                               std::vector<const char*>&                       additionalUndefines)
+{
+       const bool logMustPreserve = false;
+       const bool logExtraOptions = false;
+       const bool logBitcodeFiles = false;
+       const bool logAtomsBeforeSync = false;
+
+       // exit quickly if nothing to do
+       if ( _s_files.size() == 0 ) 
+               return false;
+       
+       // print out LTO version string if -v was used
+       if ( options.verbose )
+               fprintf(stderr, "%s\n", lto_get_version());
+       
+       // create optimizer and add each Reader
+       lto_code_gen_t generator = ::lto_codegen_create();
+       for (std::vector<File*>::iterator it=_s_files.begin(); it != _s_files.end(); ++it) {
+               if ( logBitcodeFiles ) fprintf(stderr, "lto_codegen_add_module(%s)\n", (*it)->path());
+               if ( ::lto_codegen_add_module(generator, (*it)->module()) )
+                       throwf("lto: could not merge in %s because %s", (*it)->path(), ::lto_get_error_message());
+       }
+
+       // add any -mllvm command line options
+       for (std::vector<const char*>::const_iterator it=options.llvmOptions->begin(); it != options.llvmOptions->end(); ++it) {
+               if ( logExtraOptions ) fprintf(stderr, "passing option to llvm: %s\n", *it);
+               ::lto_codegen_debug_options(generator, *it);
+       }
+
+       // The atom graph uses directed edges (references). Collect all references where 
+       // originating atom is not part of any LTO Reader. This allows optimizer to optimize an 
+       // external (i.e. not originated from same .o file) reference if all originating atoms are also 
+       // defined in llvm bitcode file.
+       CStringSet nonLLVMRefs;
+       CStringToAtom llvmAtoms;
+    bool hasNonllvmAtoms = false;
+       for (std::vector<const ld::Atom*>::const_iterator it = allAtoms.begin(); it != allAtoms.end(); ++it) {
+               const ld::Atom* atom = *it;
+               // only look at references that come from an atom that is not an llvm atom
+               if ( atom->contentType() != ld::Atom::typeLTOtemporary ) {
+                       if ( (atom->section().type() != ld::Section::typeMachHeader) && (atom->definition() != ld::Atom::definitionProxy) ) {
+                               hasNonllvmAtoms = true;
+                       }
+                       const ld::Atom* target;
+                       for (ld::Fixup::iterator fit=atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
+                               switch ( fit->binding ) {
+                                       case ld::Fixup::bindingDirectlyBound:
+                                               // that reference an llvm atom
+                                               if ( fit->u.target->contentType() == ld::Atom::typeLTOtemporary ) 
+                                                       nonLLVMRefs.insert(fit->u.target->name());
+                                               break;
+                                       case ld::Fixup::bindingsIndirectlyBound:
+                                               target = state.indirectBindingTable[fit->u.bindingIndex];
+                                               if ( target == NULL )
+                                                       throwf("'%s' in %s contains undefined reference", atom->name(), atom->file()->path());
+                                               assert(target != NULL);
+                                               if ( target->contentType() == ld::Atom::typeLTOtemporary )
+                                                       nonLLVMRefs.insert(target->name());
+                                       default:
+                                               break;
+                               }
+                       }
+               }
+               else {
+                       llvmAtoms[atom->name()] = (Atom*)atom;
+               }
+       }
+       // if entry point is in a llvm bitcode file, it must be preserved by LTO
+       if ( state.entryPoint!= NULL ) {
+               if ( state.entryPoint->contentType() == ld::Atom::typeLTOtemporary ) 
+                       nonLLVMRefs.insert(state.entryPoint->name());
+       }
+       
+       // deadAtoms are the atoms that the linker coalesced.  For instance weak or tentative definitions
+       // overriden by another atom.  If any of these deadAtoms are llvm atoms and they were replaced
+       // with a mach-o atom, we need to tell the lto engine to preserve (not optimize away) its dead 
+       // atom so that the linker can replace it with the mach-o one later.
+       CStringToAtom deadllvmAtoms;
+       for (std::vector<const ld::Atom*>::const_iterator it = allAtoms.begin(); it != allAtoms.end(); ++it) {
+               const ld::Atom* atom = *it;
+               if ( atom->coalescedAway() && (atom->contentType() == ld::Atom::typeLTOtemporary) ) {
+                       const char* name = atom->name();
+                       if ( logMustPreserve ) fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because linker coalesce away and replace with a mach-o atom\n", name);
+                       ::lto_codegen_add_must_preserve_symbol(generator, name);
+                       deadllvmAtoms[name] = (Atom*)atom;
+               }
+       }
+       for (std::vector<File*>::iterator it=_s_files.begin(); it != _s_files.end(); ++it) {
+               File* file = *it;
+               for(uint32_t i=0; i < file->_atomArrayCount; ++i) {
+                       Atom* llvmAtom = &file->_atomArray[i];
+                       if ( llvmAtom->coalescedAway()  ) {
+                               const char* name = llvmAtom->name();
+                               if ( deadllvmAtoms.find(name) == deadllvmAtoms.end() ) {
+                                       if ( logMustPreserve ) 
+                                               fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because linker coalesce away and replace with a mach-o atom\n", name);
+                                       ::lto_codegen_add_must_preserve_symbol(generator, name);
+                                       deadllvmAtoms[name] = (Atom*)llvmAtom;
+                               }
+                       }
+                       else if ( options.linkerDeadStripping && !llvmAtom->live() ) {
+                               const char* name = llvmAtom->name();
+                               deadllvmAtoms[name] = (Atom*)llvmAtom;
+                       }
+               }
+       }
+       
+       // tell code generator about symbols that must be preserved
+       for (CStringToAtom::iterator it = llvmAtoms.begin(); it != llvmAtoms.end(); ++it) {
+               const char* name = it->first;
+               Atom* atom = it->second;
+               // Include llvm Symbol in export list if it meets one of following two conditions
+               // 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 ( logMustPreserve ) fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because global symbol\n", name);
+                       ::lto_codegen_add_must_preserve_symbol(generator, name);
+               }
+               else if ( nonLLVMRefs.find(name) != nonLLVMRefs.end() ) {
+                       if ( logMustPreserve ) fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because referenced by a mach-o atom\n", name);
+                       ::lto_codegen_add_must_preserve_symbol(generator, name);
+               }
+       }
+       
+    // special case running ld -r on all bitcode files to produce another bitcode file (instead of mach-o)
+    if ( options.relocatable && !hasNonllvmAtoms ) {
+               if ( ! ::lto_codegen_write_merged_modules(generator, options.outputFilePath) ) {
+                       // HACK, no good way to tell linker we are all done, so just quit
+                       exit(0);
+               }
+               warning("could not produce merged bitcode file");
+    }
+    
+       // set code-gen model
+       lto_codegen_model model = LTO_CODEGEN_PIC_MODEL_DYNAMIC;
+       if ( options.mainExecutable ) {
+               if ( options.staticExecutable ) {
+                       // darwin x86_64 "static" code model is really dynamic code model
+                       if ( options.arch == CPU_TYPE_X86_64 )
+                               model = LTO_CODEGEN_PIC_MODEL_DYNAMIC;
+                       else
+                               model = LTO_CODEGEN_PIC_MODEL_STATIC;
+               }
+               else {
+                       if ( options.pie )
+                               model = LTO_CODEGEN_PIC_MODEL_DYNAMIC;
+                       else
+                               model = LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC;
+               }
+       }
+       else {
+               if ( options.allowTextRelocs )
+                       model = LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC;
+               else
+                       model = LTO_CODEGEN_PIC_MODEL_DYNAMIC;
+       }
+       if ( ::lto_codegen_set_pic_model(generator, model) )
+               throwf("could not create set codegen model: %s", lto_get_error_message());
+
+    // if requested, save off merged bitcode file
+    if ( options.saveTemps ) {
+        char tempBitcodePath[MAXPATHLEN];
+        strcpy(tempBitcodePath, options.outputFilePath);
+        strcat(tempBitcodePath, ".lto.bc");
+        ::lto_codegen_write_merged_modules(generator, tempBitcodePath);
+    }
+
+#if LTO_API_VERSION >= 3
+       // find assembler next to linker
+       char path[PATH_MAX];
+       uint32_t bufSize = PATH_MAX;
+       if ( _NSGetExecutablePath(path, &bufSize) != -1 ) {
+               char* lastSlash = strrchr(path, '/');
+               if ( lastSlash != NULL ) {
+                       strcpy(lastSlash+1, "as");
+                       struct stat statInfo;
+                       if ( stat(path, &statInfo) == 0 )
+                               ::lto_codegen_set_assembler_path(generator, path);
+               }
+       }
+#endif
+       // run code generator
+       size_t machOFileLen;
+       const uint8_t* machOFile = (uint8_t*)::lto_codegen_compile(generator, &machOFileLen);
+       if ( machOFile == NULL ) 
+               throwf("could not do LTO codegen: %s", ::lto_get_error_message());
+       
+    // if requested, save off temp mach-o file
+    if ( options.saveTemps ) {
+        char tempMachoPath[MAXPATHLEN];
+        strcpy(tempMachoPath, options.outputFilePath);
+        strcat(tempMachoPath, ".lto.o");
+        int fd = ::open(tempMachoPath, O_CREAT | O_WRONLY | O_TRUNC, 0666);
+               if ( fd != -1) {
+                       ::write(fd, machOFile, machOFileLen);
+                       ::close(fd);
+               }
+               //      save off merged bitcode file
+               char tempOptBitcodePath[MAXPATHLEN];
+        strcpy(tempOptBitcodePath, options.outputFilePath);
+        strcat(tempOptBitcodePath, ".lto.opt.bc");
+        ::lto_codegen_write_merged_modules(generator, tempOptBitcodePath);
+       }
+
+       // if needed, save temp mach-o file to specific location
+       if ( options.tmpObjectFilePath != NULL ) {
+               int fd = ::open(options.tmpObjectFilePath, O_CREAT | O_WRONLY | O_TRUNC, 0666);
+               if ( fd != -1) {
+                       ::write(fd, machOFile, machOFileLen);
+                       ::close(fd);
+               }
+               else {
+                       warning("could not write LTO temp file '%s', errno=%d", options.tmpObjectFilePath, errno);
+               }
+       }
+       
+       // parse generated mach-o file into a MachOReader
+       ld::relocatable::File* machoFile = parseMachOFile(machOFile, machOFileLen, nextInputOrdinal, options);
+       
+       // sync generated mach-o atoms with existing atoms ld knows about
+       if ( logAtomsBeforeSync ) {
+               fprintf(stderr, "llvmAtoms:\n");
+               for (CStringToAtom::iterator it = llvmAtoms.begin(); it != llvmAtoms.end(); ++it) {
+                       const char* name = it->first;
+                       //Atom* atom = it->second;
+                       fprintf(stderr, "\t%s\n", name);
+               }
+               fprintf(stderr, "deadllvmAtoms:\n");
+               for (CStringToAtom::iterator it = deadllvmAtoms.begin(); it != deadllvmAtoms.end(); ++it) {
+                       const char* name = it->first;
+                       //Atom* atom = it->second;
+                       fprintf(stderr, "\t%s\n", name);
+               }
+       }
+       AtomSyncer syncer(additionalUndefines, newAtoms, llvmAtoms, deadllvmAtoms, options);
+       machoFile->forEachAtom(syncer);
+                       
+       // Remove InternalAtoms from ld
+       for (std::vector<File*>::iterator it=_s_files.begin(); it != _s_files.end(); ++it) {
+               (*it)->internalAtom().setCoalescedAway();
+       }
+       // Remove Atoms from ld if code generator optimized them away
+       for (CStringToAtom::iterator li = llvmAtoms.begin(), le = llvmAtoms.end(); li != le; ++li) {
+               // check if setRealAtom() called on this Atom
+               if ( li->second->compiledAtom() == NULL ) {
+                       //fprintf(stderr, "llvm optimized away %p %s\n", li->second, li->second->name());
+                       li->second->setCoalescedAway();
+               }
+       }
+       
+       // notify about file level attributes
+       handler.doFile(*machoFile);
+       
+       // if final mach-o file has debug info, update original bitcode files to match
+       for (std::vector<File*>::iterator it=_s_files.begin(); it != _s_files.end(); ++it) {
+               (*it)->setDebugInfo(machoFile->debugInfo(), machoFile->path(),
+                                                       machoFile->modificationTime(), machoFile->cpuSubType());
+       }
+       
+       return true;
+}
+
+
+void Parser::AtomSyncer::doAtom(const ld::Atom& machoAtom)
+{
+       // update proxy atoms to point to real atoms and find new atoms
+       const char* name = machoAtom.name();
+       if ( machoAtom.scope() >= ld::Atom::scopeLinkageUnit ) {
+               CStringToAtom::iterator pos = _llvmAtoms.find(name);
+               if ( pos != _llvmAtoms.end() ) {
+                       // turn Atom into a proxy for this mach-o atom
+                       pos->second->setCompiledAtom(machoAtom);
+               }
+               else {
+                       // an atom of this name was not in the allAtoms list the linker gave us
+                       if ( _deadllvmAtoms.find(name) != _deadllvmAtoms.end() ) {
+                               // this corresponding to an atom that the linker coalesced away or marked not-live
+                               if ( _options.linkerDeadStripping ) {
+                                       // llvm seems to want this atom and -dead_strip is enabled, so it will be deleted if not needed, so add back
+                                       Atom* llvmAtom = _deadllvmAtoms[name];
+                                       llvmAtom->setCompiledAtom(machoAtom);
+                                       _newAtoms.push_back(&machoAtom);
+                               }
+                               else {
+                                       // Don't pass it back as a new atom
+                               } 
+                       }
+                       else
+                       {
+                               // this is something new that lto conjured up, tell ld its new
+                               _newAtoms.push_back(&machoAtom);
+                       }
+               }
+       }
+       else {
+               // ld only knew about non-static atoms, so this one must be new
+               _newAtoms.push_back(&machoAtom);
+       }
+       
+       // adjust fixups to go through proxy atoms
+       //fprintf(stderr, "adjusting fixups in atom: %s\n", machoAtom.name());
+       for (ld::Fixup::iterator fit=machoAtom.fixupsBegin(); fit != machoAtom.fixupsEnd(); ++fit) {
+               switch ( fit->binding ) {
+                       case ld::Fixup::bindingNone:
+                               break;
+                       case ld::Fixup::bindingByNameUnbound:
+                               // don't know if this target has been seen by linker before or if it is new
+                               // be conservative and tell linker it is new
+                               _additionalUndefines.push_back(fit->u.name);
+                               //fprintf(stderr, "    by name ref to: %s\n", fit->u.name);
+                               break;
+                       case ld::Fixup::bindingDirectlyBound:
+                               // If mach-o atom is referencing another mach-o atom then 
+                               // reference is not going through Atom proxy. Fix it here to ensure that all
+                               // llvm symbol references always go through Atom proxy.
+                               if (  fit->u.target->scope() != ld::Atom::scopeTranslationUnit ) {
+                                       const char* targetName = fit->u.target->name();
+                                       CStringToAtom::iterator pos = _llvmAtoms.find(targetName);
+                                       if ( pos != _llvmAtoms.end() ) {
+                                               fit->u.target = pos->second;
+                                       }
+                                       else {
+                                               if ( _deadllvmAtoms.find(targetName) != _deadllvmAtoms.end() ) {
+                                                       // target was coalesed away and replace by mach-o atom from a non llvm .o file
+                                                       fit->binding = ld::Fixup::bindingByNameUnbound;
+                                                       fit->u.name = targetName;
+                                               }
+                                       }
+                               }
+                               //fprintf(stderr, "    direct ref to: %s (scope=%d)\n", fit->u.target->name(), fit->u.target->scope());
+                               break;
+                       case ld::Fixup::bindingByContentBound:
+                               //fprintf(stderr, "    direct by content to: %s\n", fit->u.target->name());
+                               break;
+                       case ld::Fixup::bindingsIndirectlyBound:
+                               assert(0 && "indirect binding found in initial mach-o file?");
+                               //fprintf(stderr, "    indirect by content to: %u\n", fit->u.bindingIndex);
+                               break;
+               }
+       }
+
+}
+
+
+//
+// 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)
+{
+       return Parser::validFile(fileContent, fileLength, architecture, subarch);
+}
+
+
+//
+// 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, 
+                                                               cpu_type_t architecture, cpu_subtype_t subarch, bool logAllFiles)
+{
+       if ( Parser::validFile(fileContent, fileLength, architecture, subarch) )
+               return Parser::parse(fileContent, fileLength, path, modTime, ordinal, architecture, subarch, logAllFiles);
+       else
+               return NULL;
+}
+
+//
+// used by "ld -v" to report version of libLTO.dylib being used
+//
+const char* version()
+{
+       return ::lto_get_version();
+}
+
+
+//
+// used by ld for error reporting
+//
+bool libLTOisLoaded()
+{
+       return (::lto_get_version() != NULL);
+}
+
+//
+// used by ld for error reporting
+//
+const char* archName(const uint8_t* fileContent, uint64_t fileLength)
+{
+       return Parser::fileKind(fileContent, fileLength);
+}
+
+//
+// used by ld for doing link time optimization
+//
+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);
+}
+
+
+
+}; // namespace lto
+
+
+#endif
+
diff --git a/src/ld/parsers/lto_file.h b/src/ld/parsers/lto_file.h
new file mode 100644 (file)
index 0000000..dbb82a5
--- /dev/null
@@ -0,0 +1,73 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009-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@
+ */
+
+#ifndef __LTO_FILE_H__
+#define __LTO_FILE_H__
+
+#include "ld.hpp"
+
+namespace lto {
+
+extern const char* version();
+
+extern bool libLTOisLoaded();
+
+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, 
+                                                                       cpu_type_t architecture, cpu_subtype_t subarch, bool logAllFiles);
+
+struct OptimizeOptions {
+       const char*                                                     outputFilePath;
+       const char*                                                     tmpObjectFilePath;
+       bool                                                            allGlobalsAReDeadStripRoots;
+       bool                                                            verbose; 
+       bool                                                            saveTemps; 
+       bool                                                            pie; 
+       bool                                                            mainExecutable; 
+       bool                                                            staticExecutable; 
+       bool                                                            relocatable;
+       bool                                                            allowTextRelocs; 
+       bool                                                            linkerDeadStripping; 
+       cpu_type_t                                                      arch;
+       const std::vector<const char*>*         llvmOptions;
+};
+
+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, 
+                                               std::vector<const char*>&                       additionalUndefines);
+                                               
+} // namespace lto
+
+
+#endif // __LTO_FILE_H__
+
+
diff --git a/src/ld/parsers/macho_dylib_file.cpp b/src/ld/parsers/macho_dylib_file.cpp
new file mode 100644 (file)
index 0000000..40dad13
--- /dev/null
@@ -0,0 +1,996 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <stdint.h>
+#include <math.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/mman.h>
+
+
+#include <vector>
+#include <set>
+#include <algorithm>
+#include <ext/hash_map>
+#include <ext/hash_set>
+
+#include "Architectures.hpp"
+#include "MachOFileAbstraction.hpp"
+#include "MachOTrie.hpp"
+#include "macho_dylib_file.h"
+
+
+namespace mach_o {
+namespace dylib {
+
+
+// forward reference
+template <typename A> class File;
+
+
+//
+// An ExportAtom has no content.  It exists so that the linker can track which imported
+// symbols came from which dynamic libraries.
+//
+template <typename A>
+class ExportAtom : public ld::Atom
+{
+public:
+                                                                                       ExportAtom(const File<A>& f, const char* nm, bool weakDef, 
+                                                                                                               bool tlv, typename A::P::uint_t address)
+                                                                                               : ld::Atom(f._importProxySection, ld::Atom::definitionProxy, 
+                                                                                                       (weakDef? ld::Atom::combineByName : ld::Atom::combineNever),
+                                                                                                       ld::Atom::scopeLinkageUnit, 
+                                                                                                       (tlv ? ld::Atom::typeTLV : ld::Atom::typeUnclassified), 
+                                                                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(0)), 
+                                                                                                       _file(f), _name(nm), _address(address) {}
+       // overrides of ld::Atom
+       virtual const ld::File*                                         file() const            { return &_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 0; }
+       virtual uint64_t                                                        objectAddress() const { return _address; }
+       virtual void                                                            copyRawContent(uint8_t buffer[]) const { }
+       virtual void                                                            setScope(Scope)         { }
+
+protected:
+       typedef typename A::P                                   P;
+       typedef typename A::P::uint_t                   pint_t;
+
+       virtual                                                                 ~ExportAtom() {}
+
+       const File<A>&                                                  _file;
+       const char*                                                             _name;
+       pint_t                                                                  _address;
+};
+
+
+
+//
+// An ImportAtom has no content.  It exists so that when linking a main executable flat-namespace
+// the imports of all flat dylibs are checked
+//
+template <typename A>
+class ImportAtom : public ld::Atom
+{
+public:
+                                                                                               ImportAtom(File<A>& f, std::vector<const char*>& imports);
+
+       // overrides of ld::Atom
+       virtual ld::File*                                                       file() const            { return &_file; }
+       virtual bool                                                            translationUnitSource(const char** dir, const char** nm) const
+                                                                                                                                       { return false; }
+       virtual const char*                                                     name() const            { return "import-atom"; }
+       virtual uint64_t                                                        size() const            { return 0; }
+       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 &_undefs[0]; }
+       virtual ld::Fixup::iterator                                     fixupsEnd()     const   { return &_undefs[_undefs.size()]; }
+
+protected:
+       typedef typename A::P                                   P;
+
+       virtual                                                                 ~ImportAtom() {}
+
+
+       File<A>&                                                                _file;
+       mutable std::vector<ld::Fixup>                  _undefs;
+};
+
+template <typename A>
+ImportAtom<A>::ImportAtom(File<A>& f, std::vector<const char*>& imports)
+: ld::Atom(f._flatDummySection, ld::Atom::definitionRegular, ld::Atom::combineNever, ld::Atom::scopeTranslationUnit, 
+       ld::Atom::typeUnclassified, symbolTableNotIn, false, false, false, ld::Atom::Alignment(0)), _file(f) 
+{ 
+       for(std::vector<const char*>::iterator it=imports.begin(); it != imports.end(); ++it) {
+               _undefs.push_back(ld::Fixup(0, ld::Fixup::k1of1, ld::Fixup::kindNone, false, strdup(*it)));
+       }
+}
+
+
+
+//
+// The reader for a dylib extracts all exported symbols names from the memory-mapped
+// dylib, builds a hash table, then unmaps the file.  This is an important memory
+// savings for large dylibs.
+//
+template <typename A>
+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, 
+                                                                                                       bool linkingMainExecutable, bool hoistImplicitPublicDylibs, 
+                                                                                                       ld::MacVersionMin macMin, ld::IPhoneVersionMin iPhoneMin,
+                                                                                                       bool logAllFiles);
+       virtual                                                                 ~File() {}
+
+       // overrides of ld::File
+       virtual bool                                                    forEachAtom(ld::File::AtomHandler&) const;
+       virtual bool                                                    justInTimeforEachAtom(const char* name, ld::File::AtomHandler&) const;
+       virtual ld::File::ObjcConstraint                objCConstraint() const          { return _objcContraint; }
+       
+       // overrides of ld::dylib::File
+       virtual void                                                    processIndirectLibraries(ld::dylib::File::DylibHandler*, bool);
+       virtual bool                                                    providedExportAtom() const      { return _providedAtom; }
+       virtual const char*                                             parentUmbrella() const          { return _parentUmbrella; }
+       virtual const std::vector<const char*>* allowableClients() const        { return _allowableClients.size() != 0 ? &_allowableClients : NULL; }
+       virtual bool                                                    hasWeakExternals() const        { return _hasWeakExports; }
+       virtual bool                                                    deadStrippable() const          { return _deadStrippable; }
+       virtual bool                                                    hasPublicInstallName() const{ return _hasPublicInstallName; }
+       virtual bool                                                    hasWeakDefinition(const char* name) const;
+
+
+protected:
+
+       struct ReExportChain { ReExportChain* prev; File<A>* file; };
+
+       void                                                                                    assertNoReExportCycles(ReExportChain*);
+
+private:
+       typedef typename A::P                                   P;
+       typedef typename A::P::E                                E;
+       typedef typename A::P::uint_t                   pint_t;
+
+       friend class ExportAtom<A>;
+       friend class ImportAtom<A>;
+
+       class CStringEquals
+       {
+       public:
+               bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+       };
+       struct AtomAndWeak { ld::Atom* atom; bool weak; bool tlv; pint_t address; };
+       typedef __gnu_cxx::hash_map<const char*, AtomAndWeak, __gnu_cxx::hash<const char*>, CStringEquals> NameToAtomMap;
+       typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals>  NameSet;
+
+       struct Dependent { const char* path; File<A>* dylib; bool reExport; };
+
+       bool                                                                            containsOrReExports(const char* name, bool* weakDef, bool* tlv, pint_t* defAddress) const;
+       bool                                                                            isPublicLocation(const char* pth);
+       void                                                                            addSymbol(const char* name, bool weak, bool tlv, pint_t address);
+       void                                                                            addDyldFastStub();
+       void                                                                            buildExportHashTableFromExportInfo(const macho_dyld_info_command<P>* dyldInfo,
+                                                                                                                                                               const uint8_t* fileContent);
+       void                                                                            buildExportHashTableFromSymbolTable(const macho_dysymtab_command<P>* dynamicInfo, 
+                                                                                                               const macho_nlist<P>* symbolTable, const char* strings,
+                                                                                                               const uint8_t* fileContent);
+       static const char*                                                      objCInfoSegmentName();
+       static const char*                                                      objCInfoSectionName();
+       
+       const ld::MacVersionMin                                         _macVersionMin;
+       const ld::IPhoneVersionMin                                      _iPhoneVersionMin;
+       bool                                                                            _linkingFlat;
+       bool                                                                            _implicitlyLinkPublicDylibs;
+       ld::File::ObjcConstraint                                        _objcContraint;
+       ld::Section                                                                     _importProxySection;
+       ld::Section                                                                     _flatDummySection;
+       std::vector<Dependent>                                          _dependentDylibs;
+       std::vector<const char*>                                        _allowableClients;
+       mutable NameToAtomMap                                           _atoms;
+       NameSet                                                                         _ignoreExports;
+       const char*                                                                     _parentUmbrella;
+       ImportAtom<A>*                                                          _importAtom;
+       bool                                                                            _noRexports;
+       bool                                                                            _hasWeakExports;
+       bool                                                                            _deadStrippable;
+       bool                                                                            _hasPublicInstallName;
+       mutable bool                                                            _providedAtom;
+       bool                                                                            _explictReExportFound;
+
+       static bool                                                                     _s_logHashtable;
+};
+
+template <typename A>
+bool File<A>::_s_logHashtable = false;
+
+template <> const char* File<x86_64>::objCInfoSegmentName() { return "__DATA"; }
+template <> const char* File<arm>::objCInfoSegmentName() { return "__DATA"; }
+template <typename A> const char* File<A>::objCInfoSegmentName() { return "__OBJC"; }
+
+template <> const char* File<x86_64>::objCInfoSectionName() { return "__objc_imageinfo"; }
+template <> const char* File<arm>::objCInfoSectionName() { return "__objc_imageinfo"; }
+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,
+                               bool linkingFlatNamespace, bool linkingMainExecutable, bool hoistImplicitPublicDylibs,
+                               ld::MacVersionMin macMin, ld::IPhoneVersionMin iPhoneMin, bool logAllFiles)
+       : ld::dylib::File(strdup(pth), mTime, ord), 
+       _macVersionMin(macMin), _iPhoneVersionMin(iPhoneMin), 
+       _linkingFlat(linkingFlatNamespace), _implicitlyLinkPublicDylibs(hoistImplicitPublicDylibs),
+       _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), 
+       _deadStrippable(false), _hasPublicInstallName(false), 
+        _providedAtom(false), _explictReExportFound(false)
+{
+       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());
+
+       // write out path for -t option
+       if ( logAllFiles )
+               printf("%s\n", pth);
+
+       // a "blank" stub has zero load commands
+       if ( (header->filetype() == MH_DYLIB_STUB) && (cmd_count == 0) ) {      
+               // no further processing needed
+               munmap((caddr_t)fileContent, fileLength);
+               return;
+       }
+
+
+       // optimize the case where we know there is no reason to look at indirect dylibs
+       _noRexports = (header->flags() & MH_NO_REEXPORTED_DYLIBS) 
+                                       || (header->filetype() == MH_BUNDLE) 
+                                       || (header->filetype() == MH_EXECUTE);  // bundles and exectuables can be used via -bundle_loader
+       _hasWeakExports = (header->flags() & MH_WEAK_DEFINES);
+       _deadStrippable = (header->flags() & MH_DEAD_STRIPPABLE_DYLIB);
+       
+       // 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_nlist<P>* symbolTable = NULL;
+       const char*     strings = NULL;
+       bool compressedLinkEdit = false;
+       uint32_t dependentLibCount = 0;
+       const macho_load_command<P>* cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               macho_dylib_command<P>* dylibID;
+               const macho_symtab_command<P>* symtab;
+               switch (cmd->cmd()) {
+                       case LC_SYMTAB:
+                               symtab = (macho_symtab_command<P>*)cmd;
+                               symbolTable = (const macho_nlist<P>*)((char*)header + symtab->symoff());
+                               strings = (char*)header + symtab->stroff();
+                               break;
+                       case LC_DYSYMTAB:
+                               dynamicInfo = (macho_dysymtab_command<P>*)cmd;
+                               break;
+                       case LC_DYLD_INFO:
+                       case LC_DYLD_INFO_ONLY:
+                               dyldInfo = (macho_dyld_info_command<P>*)cmd;
+                               compressedLinkEdit = true;
+                               break;
+                       case LC_ID_DYLIB:
+                               dylibID = (macho_dylib_command<P>*)cmd;
+                               _dylibInstallPath                       = strdup(dylibID->name());
+                               _dylibTimeStamp                         = dylibID->timestamp();
+                               _dylibCurrentVersion            = dylibID->current_version();
+                               _dylibCompatibilityVersion      = dylibID->compatibility_version();
+                               _hasPublicInstallName           = isPublicLocation(_dylibInstallPath);
+                               break;
+                       case LC_LOAD_DYLIB:
+                       case LC_LOAD_WEAK_DYLIB:
+                               ++dependentLibCount;
+                               break;
+                       case LC_REEXPORT_DYLIB:
+                               _explictReExportFound = true;
+                               ++dependentLibCount;
+                               break;
+                       case LC_SUB_FRAMEWORK:
+                               _parentUmbrella = strdup(((macho_sub_framework_command<P>*)cmd)->umbrella());
+                               break;
+                       case LC_SUB_CLIENT:
+                               _allowableClients.push_back(strdup(((macho_sub_client_command<P>*)cmd)->client()));
+                               break;
+                       case macho_segment_command<P>::CMD:
+                               // check for Objective-C info
+                               if ( strcmp(((macho_segment_command<P>*)cmd)->segname(), objCInfoSegmentName()) == 0 ) {
+                                       const macho_segment_command<P>* segment = (macho_segment_command<P>*)cmd;
+                                       const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segment + sizeof(macho_segment_command<P>));
+                                       const macho_section<P>* const sectionsEnd = &sectionsStart[segment->nsects()];
+                                       for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+                                               if ( strncmp(sect->sectname(), objCInfoSectionName(), strlen(objCInfoSectionName())) == 0 ) {
+                                                       //      struct objc_image_info  {
+                                                       //              uint32_t        version;        // initially 0
+                                                       //              uint32_t        flags;
+                                                       //      };
+                                                       // #define OBJC_IMAGE_SUPPORTS_GC   2
+                                                       // #define OBJC_IMAGE_GC_ONLY       4
+                                                       //
+                                                       const uint32_t* contents = (uint32_t*)(&fileContent[sect->offset()]);
+                                                       if ( (sect->size() >= 8) && (contents[0] == 0) ) {
+                                                               uint32_t flags = E::get32(contents[1]);
+                                                               if ( (flags & 4) == 4 )
+                                                                       _objcContraint = ld::File::objcConstraintGC;
+                                                               else if ( (flags & 2) == 2 )
+                                                                       _objcContraint = ld::File::objcConstraintRetainReleaseOrGC;
+                                                               else
+                                                                       _objcContraint = ld::File::objcConstraintRetainRelease;
+                                                       }
+                                                       else if ( sect->size() > 0 ) {
+                                                               warning("can't parse %s/%s section in %s", objCInfoSegmentName(), objCInfoSectionName(), this->path());
+                                                       }
+                                               }
+                                       }
+                               }
+               }
+               cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
+               if ( cmd > cmdsEnd )
+                       throwf("malformed dylb, load command #%d is outside size of load commands in %s", i, pth);
+       }
+
+       // figure out if we need to examine dependent dylibs
+       // with compressed LINKEDIT format, MH_NO_REEXPORTED_DYLIBS can be trusted
+       bool processDependentLibraries = true;
+       if  ( compressedLinkEdit && _noRexports && !linkingFlatNamespace) 
+               processDependentLibraries = false;
+       
+       if ( processDependentLibraries ) {
+               // pass 2 builds list of all dependent libraries
+               _dependentDylibs.reserve(dependentLibCount);
+               cmd = cmds;
+               for (uint32_t i = 0; i < cmd_count; ++i) {
+                       switch (cmd->cmd()) {
+                               case LC_LOAD_DYLIB:
+                               case LC_LOAD_WEAK_DYLIB:
+                                       // with new linkedit format only care about LC_REEXPORT_DYLIB
+                                       if ( compressedLinkEdit && !linkingFlatNamespace ) 
+                                               break;
+                               case LC_REEXPORT_DYLIB:
+                                       Dependent entry;
+                                       entry.path = strdup(((macho_dylib_command<P>*)cmd)->name());
+                                       entry.dylib = NULL;
+                                       entry.reExport = (cmd->cmd() == LC_REEXPORT_DYLIB);
+                                       _dependentDylibs.push_back(entry);
+                                       break;
+                       }
+                       cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
+               }
+               // verify MH_NO_REEXPORTED_DYLIBS bit was correct
+               if ( compressedLinkEdit && !linkingFlatNamespace ) {
+                       assert(_dependentDylibs.size() != 0);
+               }
+               // pass 3 add re-export info
+               cmd = cmds;
+               for (uint32_t i = 0; i < cmd_count; ++i) {
+                       const char* frameworkLeafName;
+                       const char* dylibBaseName;
+                       switch (cmd->cmd()) {
+                               case LC_SUB_UMBRELLA:
+                                       frameworkLeafName = ((macho_sub_umbrella_command<P>*)cmd)->sub_umbrella();
+                                       for (typename std::vector<Dependent>::iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); ++it) {
+                                               const char* dylibName = it->path;
+                                               const char* lastSlash = strrchr(dylibName, '/');
+                                               if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], frameworkLeafName) == 0) )
+                                                       it->reExport = true;
+                                       }
+                                       break;
+                               case LC_SUB_LIBRARY:
+                                       dylibBaseName = ((macho_sub_library_command<P>*)cmd)->sub_library();
+                                       for (typename std::vector<Dependent>::iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); ++it) {
+                                               const char* dylibName = it->path;
+                                               const char* lastSlash = strrchr(dylibName, '/');
+                                               const char* leafStart = &lastSlash[1];
+                                               if ( lastSlash == NULL )
+                                                       leafStart = dylibName;
+                                               const char* firstDot = strchr(leafStart, '.');
+                                               int len = strlen(leafStart);
+                                               if ( firstDot != NULL )
+                                                       len = firstDot - leafStart;
+                                               if ( strncmp(leafStart, dylibBaseName, len) == 0 )
+                                                       it->reExport = true;
+                                       }
+                                       break;
+                       }
+                       cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
+               }
+       }
+       
+       // validate minimal load commands
+       if ( (_dylibInstallPath == NULL) && ((header->filetype() == MH_DYLIB) || (header->filetype() == MH_DYLIB_STUB)) ) 
+               throwf("dylib %s missing LC_ID_DYLIB load command", pth);
+       if ( dyldInfo == NULL ) {
+               if ( symbolTable == NULL )
+                       throw "binary missing LC_SYMTAB load command";
+               if ( dynamicInfo == NULL )
+                       throw "binary missing LC_DYSYMTAB load command";
+       }
+       
+       // if linking flat and this is a flat dylib, create one atom that references all imported symbols
+       if ( linkingFlatNamespace && linkingMainExecutable && ((header->flags() & MH_TWOLEVEL) == 0) ) {
+               std::vector<const char*> importNames;
+               importNames.reserve(dynamicInfo->nundefsym());
+               const macho_nlist<P>* start = &symbolTable[dynamicInfo->iundefsym()];
+               const macho_nlist<P>* end = &start[dynamicInfo->nundefsym()];
+               for (const macho_nlist<P>* sym=start; sym < end; ++sym) {
+                       importNames.push_back(&strings[sym->n_strx()]);
+               }
+               _importAtom = new ImportAtom<A>(*this, importNames);
+       }
+       
+       // build hash table
+       if ( dyldInfo != NULL ) 
+               buildExportHashTableFromExportInfo(dyldInfo, fileContent);
+       else
+               buildExportHashTableFromSymbolTable(dynamicInfo, symbolTable, strings, fileContent);
+       
+       // unmap file
+       munmap((caddr_t)fileContent, fileLength);
+}
+
+
+template <typename A>
+void File<A>::buildExportHashTableFromSymbolTable(const macho_dysymtab_command<P>* dynamicInfo, 
+                                                                                               const macho_nlist<P>* symbolTable, const char* strings, 
+                                                                                               const uint8_t* fileContent)
+{
+       if ( dynamicInfo->tocoff() == 0 ) {
+               if ( _s_logHashtable ) fprintf(stderr, "ld: building hashtable of %u toc entries for %s\n", dynamicInfo->nextdefsym(), this->path());
+               const macho_nlist<P>* start = &symbolTable[dynamicInfo->iextdefsym()];
+               const macho_nlist<P>* end = &start[dynamicInfo->nextdefsym()];
+               _atoms.resize(dynamicInfo->nextdefsym()); // set initial bucket count
+               for (const macho_nlist<P>* sym=start; sym < end; ++sym) {
+                       this->addSymbol(&strings[sym->n_strx()], (sym->n_desc() & N_WEAK_DEF) != 0, false, sym->n_value());
+               }
+       }
+       else {
+               int32_t count = dynamicInfo->ntoc();
+               _atoms.resize(count); // set initial bucket count
+               if ( _s_logHashtable ) fprintf(stderr, "ld: building hashtable of %u entries for %s\n", count, this->path());
+               const struct dylib_table_of_contents* toc = (dylib_table_of_contents*)(fileContent + dynamicInfo->tocoff());
+               for (int32_t i = 0; i < count; ++i) {
+                       const uint32_t index = E::get32(toc[i].symbol_index);
+                       const macho_nlist<P>* sym = &symbolTable[index];
+                       this->addSymbol(&strings[sym->n_strx()], (sym->n_desc() & N_WEAK_DEF) != 0, false, sym->n_value());
+               }
+       }
+       
+       // special case old libSystem
+       if ( (_dylibInstallPath != NULL) && (strcmp(_dylibInstallPath, "/usr/lib/libSystem.B.dylib") == 0) )
+               addDyldFastStub();
+}
+
+
+template <typename A>
+void File<A>::buildExportHashTableFromExportInfo(const macho_dyld_info_command<P>* dyldInfo, 
+                                                                                                                               const uint8_t* fileContent)
+{
+       if ( _s_logHashtable ) fprintf(stderr, "ld: building hashtable from export info in %s\n", this->path());
+       if ( dyldInfo->export_size() > 0 ) {
+               const uint8_t* start = fileContent + dyldInfo->export_off();
+               const uint8_t* end = &start[dyldInfo->export_size()];
+               std::vector<mach_o::trie::Entry> list;
+               parseTrie(start, end, list);
+               for (std::vector<mach_o::trie::Entry>::iterator it=list.begin(); it != list.end(); ++it) 
+                       this->addSymbol(it->name, 
+                                                       it->flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION, 
+                                                       (it->flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL,
+                                                        it->address);
+       }
+}
+
+
+template <>
+void File<x86_64>::addDyldFastStub()
+{
+       addSymbol("dyld_stub_binder", false, false, 0);
+}
+
+template <>
+void File<x86>::addDyldFastStub()
+{
+       addSymbol("dyld_stub_binder", false, false, 0);
+}
+
+template <typename A>
+void File<A>::addDyldFastStub()
+{
+       // do nothing
+}
+
+template <typename A>
+void File<A>::addSymbol(const char* name, bool weakDef, bool tlv, pint_t address)
+{
+       if ( weakDef ) {
+               assert(_hasWeakExports);
+       }
+       //fprintf(stderr, "addSymbol() %s\n", name);
+       // symbols that start with $ld$ are meta-data to the static linker
+       // <rdar://problem/5182537> need way for ld and dyld to see different exported symbols in a dylib
+       if ( strncmp(name, "$ld$", 4) == 0 ) {  
+               //    $ld$ <action> $ <condition> $ <symbol-name>
+               const char* symAction = &name[4];
+               const char* symCond = strchr(symAction, '$');
+               if ( symCond != NULL ) {
+                       char curOSVers[16];
+                       if ( _macVersionMin != ld::macVersionUnset ) {
+                               sprintf(curOSVers, "$os%d.%d$", (_macVersionMin >> 16), ((_macVersionMin >> 8) & 0xFF));
+                       }
+                       else if ( _iPhoneVersionMin != ld::iPhoneVersionUnset ) {
+                               sprintf(curOSVers, "$os%d.%d$", (_iPhoneVersionMin >> 16), ((_iPhoneVersionMin >> 8) & 0xFF));
+                       }
+                       else {
+                               assert(0 && "targeting neither macosx nor iphoneos");
+                       }
+                       if ( strncmp(symCond, curOSVers, strlen(curOSVers)) == 0 ) {
+                               const char* symName = strchr(&symCond[1], '$');
+                               if ( symName != NULL ) {
+                                       ++symName;
+                                       if ( strncmp(symAction, "hide$", 5) == 0 ) {
+                                               if ( _s_logHashtable ) fprintf(stderr, "  adding %s to ignore set for %s\n", symName, this->path());
+                                               _ignoreExports.insert(strdup(symName));
+                                               return;
+                                       }
+                                       else if ( strncmp(symAction, "add$", 4) == 0 ) {
+                                               this->addSymbol(symName, weakDef, false, 0);
+                                               return;
+                                       }
+                                       else {
+                                               warning("bad symbol action: %s in dylib %s", name, this->path());
+                                       }
+                               }
+                       }
+               }       
+               else {
+                       warning("bad symbol condition: %s in dylib %s", name, this->path());
+               }
+       }
+       
+       // add symbol as possible export if we are not supposed to ignore it
+       if ( _ignoreExports.count(name) == 0 ) {
+               AtomAndWeak bucket;
+               bucket.atom = NULL;
+               bucket.weak = weakDef;
+               bucket.tlv = tlv;
+               bucket.address = address;
+               if ( _s_logHashtable ) fprintf(stderr, "  adding %s to hash table for %s\n", name, this->path());
+               _atoms[strdup(name)] = bucket;
+       }
+}
+
+
+template <typename A>
+bool File<A>::forEachAtom(ld::File::AtomHandler& handler) const
+{
+       handler.doFile(*this);
+       // if doing flatnamespace and need all this dylib's imports resolve
+       // add atom which references alls undefines in this dylib
+       if ( _importAtom != NULL ) {
+               handler.doAtom(*_importAtom);
+               return true;
+       }
+       return false;
+}
+
+template <typename A>
+bool File<A>::hasWeakDefinition(const char* name) const
+{
+       // if supposed to ignore this export, then pretend I don't have it
+       if ( _ignoreExports.count(name) != 0 )
+               return false;
+               
+       typename NameToAtomMap::const_iterator pos = _atoms.find(name);
+       if ( pos != _atoms.end() ) {
+               return pos->second.weak;
+       }
+       else {
+               // look in children that I re-export
+               for (typename std::vector<Dependent>::const_iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); ++it) {
+                       if ( it->reExport ) {
+                               //fprintf(stderr, "getJustInTimeAtomsFor: %s NOT found in %s, looking in child %s\n", name, this->path(), (*it)->getInstallPath());
+                               typename NameToAtomMap::iterator cpos = it->dylib->_atoms.find(name);
+                               if ( cpos != it->dylib->_atoms.end() ) 
+                                       return cpos->second.weak;
+                       }
+               }
+       }
+       return false;
+}
+
+template <typename A>
+bool File<A>::containsOrReExports(const char* name, bool* weakDef, bool* tlv, pint_t* defAddress) const
+{
+       // check myself
+       typename NameToAtomMap::iterator pos = _atoms.find(name);
+       if ( pos != _atoms.end() ) {
+               *weakDef = pos->second.weak;
+               *tlv = pos->second.tlv;
+               *defAddress = pos->second.address;
+               return true;
+       }
+       
+       // check dylibs I re-export
+       for (typename std::vector<Dependent>::const_iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); ++it) {
+               if ( it->reExport && !it->dylib->implicitlyLinked() ) {
+                       if ( it->dylib->containsOrReExports(name, weakDef, tlv, defAddress) )
+                               return true;
+               }
+       }
+               
+       return false;
+}
+
+
+template <typename A>
+bool File<A>::justInTimeforEachAtom(const char* name, ld::File::AtomHandler& handler) const
+{
+       // if supposed to ignore this export, then pretend I don't have it
+       if ( _ignoreExports.count(name) != 0 )
+               return false;
+       
+       
+       AtomAndWeak bucket;
+       if ( this->containsOrReExports(name, &bucket.weak, &bucket.tlv, &bucket.address) ) {
+               bucket.atom = new ExportAtom<A>(*this, name, bucket.weak, bucket.tlv, bucket.address);
+               _atoms[name] = bucket;
+               _providedAtom = true;
+               if ( _s_logHashtable ) fprintf(stderr, "getJustInTimeAtomsFor: %s found in %s\n", name, this->path());
+               // call handler with new export atom
+               handler.doAtom(*bucket.atom);
+               return true;
+       }
+        
+       return false;
+}
+
+
+
+template <typename A>
+bool File<A>::isPublicLocation(const char* pth)
+{
+       // -no_implicit_dylibs disables this optimization
+       if ( ! _implicitlyLinkPublicDylibs )
+               return false;
+       
+       // /usr/lib is a public location
+       if ( (strncmp(pth, "/usr/lib/", 9) == 0) && (strchr(&pth[9], '/') == NULL) )
+               return true;
+
+       // /System/Library/Frameworks/ is a public location
+       if ( strncmp(pth, "/System/Library/Frameworks/", 27) == 0 ) {
+               const char* frameworkDot = strchr(&pth[27], '.');
+               // but only top level framework
+               // /System/Library/Frameworks/Foo.framework/Versions/A/Foo                 ==> true
+               // /System/Library/Frameworks/Foo.framework/Resources/libBar.dylib         ==> false
+               // /System/Library/Frameworks/Foo.framework/Frameworks/Bar.framework/Bar   ==> false
+               // /System/Library/Frameworks/Foo.framework/Frameworks/Xfoo.framework/XFoo ==> false
+               if ( frameworkDot != NULL ) {
+                       int frameworkNameLen = frameworkDot - &pth[27];
+                       if ( strncmp(&pth[strlen(pth)-frameworkNameLen-1], &pth[26], frameworkNameLen+1) == 0 )
+                               return true;
+               }
+       }
+               
+       return false;
+}
+
+template <typename A>
+void File<A>::processIndirectLibraries(ld::dylib::File::DylibHandler* handler, bool addImplicitDylibs)
+{
+       const static bool log = false;
+       if ( log ) fprintf(stderr, "processIndirectLibraries(%s)\n", this->installPath());
+       if ( _linkingFlat ) {
+               for (typename std::vector<Dependent>::iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); it++) {
+                       it->dylib = (File<A>*)handler->findDylib(it->path, this->path());
+               }
+       }
+       else if ( _noRexports ) {
+               // MH_NO_REEXPORTED_DYLIBS bit set, then nothing to do
+       }
+       else {
+               // two-level, might have re-exports
+               for (typename std::vector<Dependent>::iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); it++) {
+                       if ( it->reExport ) {
+                               if ( log ) fprintf(stderr, "processIndirectLibraries() parent=%s, child=%s\n", this->installPath(), it->path);
+                               // a LC_REEXPORT_DYLIB, LC_SUB_UMBRELLA or LC_SUB_LIBRARY says we re-export this child
+                               it->dylib = (File<A>*)handler->findDylib(it->path, this->path());
+                               if ( it->dylib->hasPublicInstallName() ) {
+                                       // promote this child to be automatically added as a direct dependent if this already is
+                                       if ( (this->explicitlyLinked() || this->implicitlyLinked()) && (strcmp(it->path,it->dylib->installPath()) == 0) ) {
+                                               if ( log ) fprintf(stderr, "processIndirectLibraries() implicitly linking %s\n", it->dylib->installPath());
+                                               it->dylib->setImplicitlyLinked();
+                                       }
+                                       else if ( it->dylib->explicitlyLinked() || it->dylib->implicitlyLinked() ) {
+                                               if ( log ) fprintf(stderr, "processIndirectLibraries() parent is not directly linked, but child is, so no need to re-export child\n");
+                                       }
+                                       else {
+                                               if ( log ) fprintf(stderr, "processIndirectLibraries() parent is not directly linked, so parent=%s will re-export child=%s\n", this->installPath(), it->path);
+                                       }
+                               }
+                               else {
+                                       // add all child's symbols to me
+                                       if ( log ) fprintf(stderr, "processIndirectLibraries() child is not public, so parent=%s will re-export child=%s\n", this->installPath(), it->path);
+                               }
+                       }
+                       else if ( !_explictReExportFound ) {
+                               // see if child contains LC_SUB_FRAMEWORK with my name
+                               it->dylib = (File<A>*)handler->findDylib(it->path, this->path());
+                               const char* parentUmbrellaName = it->dylib->parentUmbrella();
+                               if ( parentUmbrellaName != NULL ) {
+                                       const char* parentName = this->path();
+                                       const char* lastSlash = strrchr(parentName, '/');
+                                       if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], parentUmbrellaName) == 0) ) {
+                                               // add all child's symbols to me
+                                               it->reExport = true;
+                                               if ( log ) fprintf(stderr, "processIndirectLibraries() umbrella=%s will re-export child=%s\n", this->installPath(), it->path);
+                                       }
+                               }
+                       }
+               }
+       }
+       
+       // check for re-export cycles
+       ReExportChain chain;
+       chain.prev = NULL;
+       chain.file = this;
+       this->assertNoReExportCycles(&chain);
+}
+
+template <typename A>
+void File<A>::assertNoReExportCycles(ReExportChain* prev)
+{
+       // recursively check my re-exported dylibs
+       ReExportChain chain;
+       chain.prev = prev;
+       chain.file = this;
+       for (typename std::vector<Dependent>::iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); it++) {
+               if ( it->reExport ) {
+                       ld::File* child = it->dylib;
+                       // check child is not already in chain 
+                       for (ReExportChain* p = prev; p != NULL; p = p->prev) {
+                               if ( p->file == child ) {
+                                       throwf("cycle in dylib re-exports with %s and %s", child->path(), this->path());
+                               }
+                       }
+                       if ( it->dylib != NULL )
+                               it->dylib->assertNoReExportCycles(&chain);
+               }
+       }
+}
+
+
+struct ParserOptions {
+       bool                                    linkingFlat;
+       bool                                    linkingMain;
+       bool                                    addImplictDylibs;
+       ld::MacVersionMin               macOSMin;
+       ld::IPhoneVersionMin    iphoneOSMin;
+};
+
+
+template <typename A>
+class Parser 
+{
+public:
+       typedef typename A::P                                   P;
+
+       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) {
+                                                                                                                        return new File<A>(fileContent, fileLength, path, mTime,
+                                                                                                                                                       ordinal, opts.flatNamespace(), 
+                                                                                                                                                       opts.linkingMainExecutable(),
+                                                                                                                                                       opts.implicitlyLinkIndirectPublicDylibs(), 
+                                                                                                                                                       opts.macosxVersionMin(), 
+                                                                                                                                                       opts.iphoneOSVersionMin(),
+                                                                                                                                                       opts.logAllFiles());
+                                                                                                               }
+
+};
+
+
+
+template <>
+bool Parser<ppc>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle)
+{
+       const macho_header<P>* header = (const macho_header<P>*)fileContent;
+       if ( header->magic() != MH_MAGIC )
+               return false;
+       if ( header->cputype() != CPU_TYPE_POWERPC )
+               return false;
+       switch ( header->filetype() ) {
+               case MH_DYLIB:
+               case MH_DYLIB_STUB:
+                       return true;
+               case MH_BUNDLE:
+                       if ( executableOrDyliborBundle )
+                               return true;
+                       else
+                               throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
+               case MH_EXECUTE:
+                       if ( executableOrDyliborBundle )
+                               return true;
+                       else
+                               throw "can't link with a main executable";
+               default:
+                       return false;
+       }
+}
+
+template <>
+bool Parser<ppc64>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle)
+{
+       const macho_header<P>* header = (const macho_header<P>*)fileContent;
+       if ( header->magic() != MH_MAGIC_64 )
+               return false;
+       if ( header->cputype() != CPU_TYPE_POWERPC64 )
+               return false;
+       switch ( header->filetype() ) {
+               case MH_DYLIB:
+               case MH_DYLIB_STUB:
+                       return true;
+               case MH_BUNDLE:
+                       if ( executableOrDyliborBundle )
+                               return true;
+                       else
+                               throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
+               case MH_EXECUTE:
+                       if ( executableOrDyliborBundle )
+                               return true;
+                       else
+                               throw "can't link with a main executable";
+               default:
+                       return false;
+       }
+}
+
+template <>
+bool Parser<x86>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle)
+{
+       const macho_header<P>* header = (const macho_header<P>*)fileContent;
+       if ( header->magic() != MH_MAGIC )
+               return false;
+       if ( header->cputype() != CPU_TYPE_I386 )
+               return false;
+       switch ( header->filetype() ) {
+               case MH_DYLIB:
+               case MH_DYLIB_STUB:
+                       return true;
+               case MH_BUNDLE:
+                       if ( executableOrDyliborBundle )
+                               return true;
+                       else
+                               throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
+               case MH_EXECUTE:
+                       if ( executableOrDyliborBundle )
+                               return true;
+                       else
+                               throw "can't link with a main executable";
+               default:
+                       return false;
+       }
+}
+
+template <>
+bool Parser<x86_64>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle)
+{
+       const macho_header<P>* header = (const macho_header<P>*)fileContent;
+       if ( header->magic() != MH_MAGIC_64 )
+               return false;
+       if ( header->cputype() != CPU_TYPE_X86_64 )
+               return false;
+       switch ( header->filetype() ) {
+               case MH_DYLIB:
+               case MH_DYLIB_STUB:
+                       return true;
+               case MH_BUNDLE:
+                       if ( executableOrDyliborBundle )
+                               return true;
+                       else
+                               throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
+               case MH_EXECUTE:
+                       if ( executableOrDyliborBundle )
+                               return true;
+                       else
+                               throw "can't link with a main executable";
+               default:
+                       return false;
+       }
+}
+
+template <>
+bool Parser<arm>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle)
+{
+       const macho_header<P>* header = (const macho_header<P>*)fileContent;
+       if ( header->magic() != MH_MAGIC )
+               return false;
+       if ( header->cputype() != CPU_TYPE_ARM )
+               return false;
+       switch ( header->filetype() ) {
+               case MH_DYLIB:
+               case MH_DYLIB_STUB:
+                       return true;
+               case MH_BUNDLE:
+                       if ( executableOrDyliborBundle )
+                               return true;
+                       else
+                               throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
+               case MH_EXECUTE:
+                       if ( executableOrDyliborBundle )
+                               return true;
+                       else
+                               throw "can't link with a main executable";
+               default:
+                       return false;
+       }
+}
+
+
+
+//
+// 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, bool bundleLoader)
+{
+       switch ( opts.architecture() ) {
+               case CPU_TYPE_X86_64:
+                       if ( Parser<x86_64>::validFile(fileContent, bundleLoader) )
+                               return Parser<x86_64>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
+                       break;
+               case CPU_TYPE_I386:
+                       if ( Parser<x86>::validFile(fileContent, bundleLoader) )
+                               return Parser<x86>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
+                       break;
+               case CPU_TYPE_ARM:
+                       if ( Parser<arm>::validFile(fileContent, bundleLoader) )
+                               return Parser<arm>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
+                       break;
+               case CPU_TYPE_POWERPC:
+                       if ( Parser<ppc>::validFile(fileContent, bundleLoader) )
+                               return Parser<ppc>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
+                       break;
+               case CPU_TYPE_POWERPC64:
+                       if ( Parser<ppc64>::validFile(fileContent, bundleLoader) )
+                               return Parser<ppc64>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
+                       break;
+       }
+       return NULL;
+}
+
+
+}; // namespace dylib
+}; // namespace mach_o
+
+
diff --git a/src/ld/parsers/macho_dylib_file.h b/src/ld/parsers/macho_dylib_file.h
new file mode 100644 (file)
index 0000000..5c858e2
--- /dev/null
@@ -0,0 +1,41 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __MACHO_DYLIB_FILE_H__
+#define __MACHO_DYLIB_FILE_H__
+
+#include "ld.hpp"
+#include "Options.h"
+
+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, bool bundleLoader);
+
+} // namespace dylib
+} // namespace mach_o
+
+
+#endif // __MACHO_DYLIB_FILE_H__
diff --git a/src/ld/parsers/macho_relocatable_file.cpp b/src/ld/parsers/macho_relocatable_file.cpp
new file mode 100644 (file)
index 0000000..25c1965
--- /dev/null
@@ -0,0 +1,6552 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2009-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <math.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include "MachOFileAbstraction.hpp"
+
+#include <libunwind/DwarfInstructions.hpp>
+#include <libunwind/AddressSpace.hpp>
+#include <libunwind/Registers.hpp>
+
+#include <vector>
+#include <set>
+#include <map>
+#include <algorithm>
+
+#include "dwarf2.h"
+#include "debugline.h"
+
+#include "Architectures.hpp"
+#include "ld.hpp"
+#include "macho_relocatable_file.h"
+
+
+
+extern void throwf(const char* format, ...) __attribute__ ((noreturn,format(printf, 1, 2)));
+extern void warning(const char* format, ...) __attribute__((format(printf, 1, 2)));
+
+namespace mach_o {
+namespace relocatable {
+
+
+// forward reference
+template <typename A> class Parser;
+template <typename A> class Atom;
+template <typename A> class Section;
+template <typename A> class CFISection;
+
+template <typename A>
+class File : public ld::relocatable::File
+{
+public:
+                                                                                       File(const char* p, time_t mTime, const uint8_t* content, uint32_t ord) :
+                                                                                               ld::relocatable::File(p,mTime,ord), _fileContent(content),
+                                                                                               _sectionsArray(NULL), _atomsArray(NULL),
+                                                                                               _sectionsArrayCount(0), _atomsArrayCount(0),
+                                                                                               _debugInfoKind(ld::relocatable::File::kDebugInfoNone),
+                                                                                               _dwarfTranslationUnitDir(NULL), _dwarfTranslationUnitFile(NULL),
+                                                                                               _dwarfDebugInfoSect(NULL), _dwarfDebugAbbrevSect(NULL), 
+                                                                                               _dwarfDebugLineSect(NULL), _dwarfDebugStringSect(NULL), 
+                                                                                               _objConstraint(ld::File::objcConstraintNone),
+                                                                                               _cpuSubType(0),
+                                                                                               _ojcReplacmentClass(false),  _canScatterAtoms(false) {}
+       virtual                                                                 ~File();
+
+       // overrides of ld::File
+       virtual bool                                                                            forEachAtom(ld::File::AtomHandler&) const;
+       virtual bool                                                                            justInTimeforEachAtom(const char* name, ld::File::AtomHandler&) const
+                                                                                                                                                                       { 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; }
+       virtual const std::vector<ld::relocatable::File::Stab>* stabs() const                                   { return &_stabs; }
+       virtual bool                                                                            canScatterAtoms() const                 { return _canScatterAtoms; }
+       bool                                                                                            translationUnitSource(const char** dir, const char** name) const;
+       
+       const uint8_t*                                                                          fileContent()                                   { return _fileContent; }
+private:
+       friend class Atom<A>;
+       friend class Section<A>;
+       friend class Parser<A>;
+       friend class CFISection<A>::OAS;
+       
+       typedef typename A::P                                   P;
+       
+       const uint8_t*                                                  _fileContent;
+       Section<A>**                                                    _sectionsArray;
+       uint8_t*                                                                _atomsArray;
+       uint32_t                                                                _sectionsArrayCount;
+       uint32_t                                                                _atomsArrayCount;
+       std::vector<ld::Fixup>                                  _fixups;
+       std::vector<ld::Atom::UnwindInfo>               _unwindInfos;
+       std::vector<ld::Atom::LineInfo>                 _lineInfos;
+       std::vector<ld::relocatable::File::Stab>_stabs;
+       ld::relocatable::File::DebugInfoKind    _debugInfoKind;
+       const char*                                                             _dwarfTranslationUnitDir;
+       const char*                                                             _dwarfTranslationUnitFile;
+       const macho_section<P>*                                 _dwarfDebugInfoSect;
+       const macho_section<P>*                                 _dwarfDebugAbbrevSect;
+       const macho_section<P>*                                 _dwarfDebugLineSect;
+       const macho_section<P>*                                 _dwarfDebugStringSect;
+       ld::File::ObjcConstraint                                _objConstraint;
+       uint32_t                                                                _cpuSubType;
+       bool                                                                    _ojcReplacmentClass;
+       bool                                                                    _canScatterAtoms;
+};
+
+
+template <typename A>
+class Section : public ld::Section
+{
+public:
+       typedef typename A::P::uint_t   pint_t;
+       typedef typename A::P                   P;
+       typedef typename A::P::E                E;
+
+       virtual                                                 ~Section()                                      { }
+       class File<A>&                                  file() const                            { return _file; }
+       const macho_section<P>*                 machoSection() const            { return _machOSection; }
+       uint32_t                                                sectionNum(class Parser<A>&) const;
+       virtual ld::Atom::Alignment             alignmentForAddress(pint_t addr);
+       virtual ld::Atom::ContentType   contentType()                           { return ld::Atom::typeUnclassified; }
+       virtual bool                                    dontDeadStrip()                         { return (this->_machOSection->flags() & S_ATTR_NO_DEAD_STRIP); }
+       virtual Atom<A>*                                findAtomByAddress(pint_t addr) { return this->findContentAtomByAddress(addr, this->_beginAtoms, this->_endAtoms); }
+       virtual bool                                    addFollowOnFixups() const       { return ! _file.canScatterAtoms(); }
+       virtual uint32_t                                appendAtoms(class Parser<A>& parser, uint8_t* buffer, 
+                                                                                               struct Parser<A>::LabelAndCFIBreakIterator& it, 
+                                                                                               const struct Parser<A>::CFIInfoArray&) = 0;
+       virtual uint32_t                                computeAtomCount(class Parser<A>& parser, 
+                                                                                                               struct Parser<A>::LabelAndCFIBreakIterator& it, 
+                                                                                                               const struct Parser<A>::CFIInfoArray&) = 0;
+       virtual void                                    makeFixups(class Parser<A>& parser, const struct Parser<A>::CFIInfoArray&);
+       virtual bool                                    addRelocFixup(class Parser<A>& parser, const macho_relocation_info<P>*);
+       virtual unsigned long                   contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const { return 0; }
+       virtual bool                                    canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs, 
+                                                                                                       const ld::IndirectBindingTable& ind) const { return false; }
+
+protected:     
+                                               Section(File<A>& f, const macho_section<typename A::P>* s)
+                                                       : ld::Section(makeSegmentName(s), makeSectionName(s), sectionType(s)),
+                                                               _file(f), _machOSection(s), _beginAtoms(NULL), _endAtoms(NULL), _hasAliases(false) { }
+                                               Section(File<A>& f, const char* segName, const char* sectName, ld::Section::Type t, bool hidden=false)
+                                                       : ld::Section(segName, sectName, t, hidden), _file(f), _machOSection(NULL), 
+                                                               _beginAtoms(NULL), _endAtoms(NULL), _hasAliases(false) { }
+
+
+       bool                                                    addRelocFixup_powerpc(class Parser<A>& parser,const macho_relocation_info<typename A::P>* reloc);
+       Atom<A>*                                                findContentAtomByAddress(pint_t addr, class Atom<A>* start, class Atom<A>* end);
+       uint32_t                                                x86_64PcRelOffset(uint8_t r_type);
+       static const char*                              makeSegmentName(const macho_section<typename A::P>* s);
+       static const char*                              makeSectionName(const macho_section<typename A::P>* s);
+       static bool                                             readable(const macho_section<typename A::P>* s);
+       static bool                                             writable(const macho_section<typename A::P>* s);
+       static bool                                             exectuable(const macho_section<typename A::P>* s);
+       static ld::Section::Type                sectionType(const macho_section<typename A::P>* s);
+       
+       File<A>&                                                _file;
+       const macho_section<P>*                 _machOSection;
+       class Atom<A>*                                  _beginAtoms;
+       class Atom<A>*                                  _endAtoms;
+       bool                                                    _hasAliases;
+};
+
+
+template <typename A>
+class CFISection : public Section<A>
+{
+public:
+                                               CFISection(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
+                                                       : Section<A>(f, s) { }
+       uint32_t                        cfiCount();
+
+       virtual ld::Atom::ContentType   contentType()           { return ld::Atom::typeCFI; }
+       virtual uint32_t        computeAtomCount(class Parser<A>& parser, struct Parser<A>::LabelAndCFIBreakIterator& it, const struct Parser<A>::CFIInfoArray&);
+       virtual uint32_t        appendAtoms(class Parser<A>& parser, uint8_t* buffer, struct Parser<A>::LabelAndCFIBreakIterator& it, const struct Parser<A>::CFIInfoArray&);
+       virtual void            makeFixups(class Parser<A>& parser, const struct Parser<A>::CFIInfoArray&);
+       virtual bool            addFollowOnFixups() const       { return false; }
+
+
+       ///
+       /// ObjectFileAddressSpace is used as a template parameter to UnwindCursor for parsing
+       /// dwarf CFI information in an object file.   
+       ///
+       class OAS
+       {
+       public:
+                       typedef typename A::P::uint_t   pint_t;
+                       typedef typename A::P                   P;
+                       typedef typename A::P::E                E;
+                       typedef typename A::P::uint_t   sint_t;
+
+                                                       OAS(CFISection<A>& ehFrameSection, const uint8_t* ehFrameBuffer) : 
+                                                               _ehFrameSection(ehFrameSection),
+                                                               _ehFrameContent(ehFrameBuffer), 
+                                                               _ehFrameStartAddr(ehFrameSection.machoSection()->addr()), 
+                                                               _ehFrameEndAddr(ehFrameSection.machoSection()->addr()+ehFrameSection.machoSection()->size()) {}
+
+                       uint8_t                 get8(pint_t addr) { return *((uint8_t*)mappedAddress(addr)); }
+                       uint16_t                get16(pint_t addr)      { return E::get16(*((uint16_t*)mappedAddress(addr))); }
+                       uint32_t                get32(pint_t addr)      { return E::get32(*((uint32_t*)mappedAddress(addr))); }
+                       uint64_t                get64(pint_t addr)      { return E::get64(*((uint64_t*)mappedAddress(addr))); }
+                       pint_t                  getP(pint_t addr)       { return P::getP(*((pint_t*)mappedAddress(addr))); }
+                       uint64_t                getULEB128(pint_t& addr, pint_t end);
+                       int64_t                 getSLEB128(pint_t& addr, pint_t end);
+                       pint_t                  getEncodedP(pint_t& addr, pint_t end, uint8_t encoding);
+       private:
+               const void*                     mappedAddress(pint_t addr);
+               
+               CFISection<A>&                          _ehFrameSection;
+               const uint8_t*                          _ehFrameContent;
+               pint_t                                          _ehFrameStartAddr;
+               pint_t                                          _ehFrameEndAddr;
+       };
+
+
+       typedef typename A::P::uint_t                   pint_t;
+       typedef libunwind::CFI_Atom_Info<OAS>   CFI_Atom_Info;
+       
+       void                            cfiParse(class Parser<A>& parser, uint8_t* buffer, CFI_Atom_Info cfiArray[], uint32_t cfiCount);
+       bool                            needsRelocating();
+
+       static bool                     bigEndian();
+private:
+       void                            addCiePersonalityFixups(class Parser<A>& parser, const CFI_Atom_Info* cieInfo);
+       static void                     warnFunc(void* ref, uint64_t funcAddr, const char* msg);
+};
+
+
+template <typename A>
+class TentativeDefinitionSection : public Section<A>
+{
+public:
+                                               TentativeDefinitionSection(Parser<A>& parser, File<A>& f)
+                                                       : Section<A>(f, "__DATA", "__comm/tent", ld::Section::typeTentativeDefs)  {}
+
+       virtual ld::Atom::ContentType   contentType()           { return ld::Atom::typeZeroFill; }
+       virtual bool            addFollowOnFixups() const       { return false; }
+       virtual Atom<A>*        findAtomByAddress(typename A::P::uint_t addr) { throw "TentativeDefinitionSection::findAtomByAddress() should never be called"; }
+       virtual uint32_t        computeAtomCount(class Parser<A>& parser, struct Parser<A>::LabelAndCFIBreakIterator& it, 
+                                                                                       const struct Parser<A>::CFIInfoArray&);
+       virtual uint32_t        appendAtoms(class Parser<A>& parser, uint8_t* buffer, 
+                                                                               struct Parser<A>::LabelAndCFIBreakIterator& it, 
+                                                                               const struct Parser<A>::CFIInfoArray&);
+       virtual void            makeFixups(class Parser<A>& parser, const struct Parser<A>::CFIInfoArray&) {}
+private:
+       typedef typename A::P::uint_t   pint_t;
+       typedef typename A::P                   P;
+};
+
+
+template <typename A>
+class AbsoluteSymbolSection : public Section<A>
+{
+public:
+                                               AbsoluteSymbolSection(Parser<A>& parser, File<A>& f)
+                                                       : Section<A>(f, "__DATA", "__abs", ld::Section::typeAbsoluteSymbols, true)  {}
+
+       virtual ld::Atom::ContentType   contentType()           { return ld::Atom::typeUnclassified; }
+       virtual bool                                    dontDeadStrip()         { return false; }
+       virtual ld::Atom::Alignment             alignmentForAddress(typename A::P::uint_t addr) { return ld::Atom::Alignment(0); }
+       virtual bool            addFollowOnFixups() const       { return false; }
+       virtual Atom<A>*        findAtomByAddress(typename A::P::uint_t addr) { throw "AbsoluteSymbolSection::findAtomByAddress() should never be called"; }
+       virtual uint32_t        computeAtomCount(class Parser<A>& parser, struct Parser<A>::LabelAndCFIBreakIterator& it, 
+                                                                                       const struct Parser<A>::CFIInfoArray&);
+       virtual uint32_t        appendAtoms(class Parser<A>& parser, uint8_t* buffer, 
+                                                                               struct Parser<A>::LabelAndCFIBreakIterator& it, 
+                                                                               const struct Parser<A>::CFIInfoArray&);
+       virtual void            makeFixups(class Parser<A>& parser, const struct Parser<A>::CFIInfoArray&) {}
+       virtual Atom<A>*        findAbsAtomForValue(typename A::P::uint_t);
+       
+private:
+       typedef typename A::P::uint_t   pint_t;
+       typedef typename A::P                   P;
+};
+
+
+template <typename A>
+class SymboledSection : public Section<A>
+{
+public:
+                                               SymboledSection(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s);
+       virtual ld::Atom::ContentType   contentType() { return _type; }
+       virtual bool                                    dontDeadStrip();
+       virtual uint32_t        computeAtomCount(class Parser<A>& parser, struct Parser<A>::LabelAndCFIBreakIterator& it, 
+                                                                                       const struct Parser<A>::CFIInfoArray&);
+       virtual uint32_t        appendAtoms(class Parser<A>& parser, uint8_t* buffer, 
+                                                                       struct Parser<A>::LabelAndCFIBreakIterator& it, 
+                                                                       const struct Parser<A>::CFIInfoArray&);
+protected:
+       typedef typename A::P::uint_t   pint_t;
+       typedef typename A::P                   P;
+
+       ld::Atom::ContentType                   _type;
+};
+
+
+template <typename A>
+class TLVDefsSection : public SymboledSection<A>
+{
+public:
+                                               TLVDefsSection(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s) :
+                                                       SymboledSection<A>(parser, f, s) { }
+
+private:
+
+};
+
+
+template <typename A>
+class ImplicitSizeSection : public Section<A>
+{
+public:
+                                               ImplicitSizeSection(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
+                                                       : Section<A>(f, s) { }
+       virtual uint32_t        computeAtomCount(class Parser<A>& parser, struct Parser<A>::LabelAndCFIBreakIterator& it, const struct Parser<A>::CFIInfoArray&);
+       virtual uint32_t        appendAtoms(class Parser<A>& parser, uint8_t* buffer, struct Parser<A>::LabelAndCFIBreakIterator& it, const struct Parser<A>::CFIInfoArray&);
+protected:
+       typedef typename A::P::uint_t   pint_t;
+       typedef typename A::P                   P;
+       
+       virtual bool                                            addFollowOnFixups() const               { return false; }
+       virtual const char*                                     unlabeledAtomName(Parser<A>& parser, pint_t addr) = 0;
+       virtual ld::Atom::SymbolTableInclusion  symbolTableInclusion()          { return ld::Atom::symbolTableNotIn; }
+       virtual pint_t                                          elementSizeAtAddress(pint_t addr) = 0;
+       virtual ld::Atom::Scope                         scopeAtAddress(Parser<A>& parser, pint_t addr) { return ld::Atom::scopeLinkageUnit; }
+       virtual bool                                            useElementAt(Parser<A>& parser, 
+                                                                                               struct Parser<A>::LabelAndCFIBreakIterator& it, pint_t addr) = 0;
+       virtual ld::Atom::Definition            definition()                                    { return ld::Atom::definitionRegular; }
+       virtual ld::Atom::Combine                       combine(Parser<A>& parser, pint_t addr) = 0;
+       virtual bool                                            ignoreLabel(const char* label)  { return (label[0] == 'L'); }
+};
+
+template <typename A>
+class FixedSizeSection : public ImplicitSizeSection<A>
+{
+public:
+                                               FixedSizeSection(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
+                                                       : ImplicitSizeSection<A>(parser, f, s) { }
+protected:
+       typedef typename A::P::uint_t   pint_t;
+       typedef typename A::P                   P;
+       typedef typename A::P::E                E;
+       
+       virtual bool                                    useElementAt(Parser<A>& parser, 
+                                                                               struct Parser<A>::LabelAndCFIBreakIterator& it, pint_t addr) 
+                                                                                                               { return true; }
+};
+
+
+template <typename A>
+class Literal4Section : public FixedSizeSection<A>
+{
+public:
+                                               Literal4Section(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
+                                                       : FixedSizeSection<A>(parser, f, s) {}
+protected:
+       typedef typename A::P::uint_t   pint_t;
+       typedef typename A::P                   P;
+
+       virtual ld::Atom::Alignment             alignmentForAddress(pint_t addr)                { return ld::Atom::Alignment(2); }
+       virtual const char*                             unlabeledAtomName(Parser<A>&, pint_t)   { return "4-byte-literal"; }
+       virtual pint_t                                  elementSizeAtAddress(pint_t addr)               { return 4; }
+       virtual ld::Atom::Combine               combine(Parser<A>&, pint_t)                             { return ld::Atom::combineByNameAndContent; }
+       virtual unsigned long                   contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
+       virtual bool                                    canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs, 
+                                                                                                       const ld::IndirectBindingTable& ind) const;
+};
+
+template <typename A>
+class Literal8Section : public FixedSizeSection<A>
+{
+public:
+                                               Literal8Section(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
+                                                       : FixedSizeSection<A>(parser, f, s) {}
+protected:
+       typedef typename A::P::uint_t   pint_t;
+       typedef typename A::P                   P;
+
+       virtual ld::Atom::Alignment             alignmentForAddress(pint_t addr)                { return ld::Atom::Alignment(3); }
+       virtual const char*                             unlabeledAtomName(Parser<A>&, pint_t)   { return "8-byte-literal"; }
+       virtual pint_t                                  elementSizeAtAddress(pint_t addr)               { return 8; }
+       virtual ld::Atom::Combine               combine(Parser<A>&, pint_t)                             { return ld::Atom::combineByNameAndContent; }
+       virtual unsigned long                   contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
+       virtual bool                                    canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs, 
+                                                                                                       const ld::IndirectBindingTable& ind) const;
+};
+
+template <typename A>
+class Literal16Section : public FixedSizeSection<A>
+{
+public:
+                                               Literal16Section(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
+                                                       : FixedSizeSection<A>(parser, f, s) {}
+protected:
+       typedef typename A::P::uint_t   pint_t;
+       typedef typename A::P                   P;
+
+       virtual ld::Atom::Alignment             alignmentForAddress(pint_t addr)                { return ld::Atom::Alignment(4); }
+       virtual const char*                             unlabeledAtomName(Parser<A>&, pint_t)   { return "16-byte-literal"; }
+       virtual pint_t                                  elementSizeAtAddress(pint_t addr)               { return 16; }
+       virtual ld::Atom::Combine               combine(Parser<A>&, pint_t)                             { return ld::Atom::combineByNameAndContent; }
+       virtual unsigned long                   contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
+       virtual bool                                    canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs, 
+                                                                                                       const ld::IndirectBindingTable& ind) const;
+};
+
+
+template <typename A>
+class NonLazyPointerSection : public FixedSizeSection<A>
+{
+public:
+                                               NonLazyPointerSection(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
+                                                       : FixedSizeSection<A>(parser, f, s) {}
+protected:
+       typedef typename A::P::uint_t   pint_t;
+       typedef typename A::P                   P;
+
+       virtual void                                    makeFixups(class Parser<A>& parser, const struct Parser<A>::CFIInfoArray&);
+       virtual ld::Atom::ContentType   contentType()                                                   { return ld::Atom::typeNonLazyPointer; }
+       virtual ld::Atom::Alignment             alignmentForAddress(pint_t addr)                { return ld::Atom::Alignment(log2(sizeof(pint_t))); }
+       virtual const char*                             unlabeledAtomName(Parser<A>&, pint_t)   { return "non_lazy_ptr"; }
+       virtual pint_t                                  elementSizeAtAddress(pint_t addr)               { return sizeof(pint_t); }
+       virtual ld::Atom::Scope                 scopeAtAddress(Parser<A>& parser, pint_t addr);
+       virtual ld::Atom::Combine               combine(Parser<A>&, pint_t);
+       virtual bool                                    ignoreLabel(const char* label)                  { return true; }
+       virtual unsigned long                   contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
+       virtual bool                                    canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs, 
+                                                                                                       const ld::IndirectBindingTable& ind) const;
+
+private:
+       static const char*                              targetName(const class Atom<A>* atom, const ld::IndirectBindingTable& ind);
+       static ld::Fixup::Kind                  fixupKind();
+};
+
+
+template <typename A>
+class CFStringSection : public FixedSizeSection<A>
+{
+public:
+                                               CFStringSection(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
+                                                       : FixedSizeSection<A>(parser, f, s) {}
+protected:
+       typedef typename A::P::uint_t   pint_t;
+
+       virtual ld::Atom::Alignment             alignmentForAddress(pint_t addr)                { return ld::Atom::Alignment(log2(sizeof(pint_t))); }
+       virtual const char*                             unlabeledAtomName(Parser<A>&, pint_t)   { return "CFString"; }
+       virtual pint_t                                  elementSizeAtAddress(pint_t addr)               { return 4*sizeof(pint_t); }
+       virtual ld::Atom::Combine               combine(Parser<A>&, pint_t)                             { return ld::Atom::combineByNameAndReferences; }
+       virtual bool                                    ignoreLabel(const char* label)                  { return true; }
+       virtual unsigned long                   contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
+       virtual bool                                    canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs, 
+                                                                                                       const ld::IndirectBindingTable& ind) const;
+private:
+       enum ContentType { contentUTF8, contentUTF16, contentUnknown };
+       static const uint8_t*                   targetContent(const class Atom<A>* atom, const ld::IndirectBindingTable& ind,
+                                                                                               ContentType* ct, unsigned int* count);
+};
+
+
+template <typename A>
+class ObjC1ClassSection : public FixedSizeSection<A>
+{
+public:
+                                               ObjC1ClassSection(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
+                                                       : FixedSizeSection<A>(parser, f, s) {}
+protected:
+       typedef typename A::P::uint_t   pint_t;
+       typedef typename A::P                   P;
+       typedef typename A::P::E                E;
+
+       virtual ld::Atom::Scope                 scopeAtAddress(Parser<A>& , pint_t )    { return ld::Atom::scopeGlobal; }
+       virtual ld::Atom::Alignment             alignmentForAddress(pint_t addr)                { return ld::Atom::Alignment(2); }
+       virtual const char*                             unlabeledAtomName(Parser<A>&, pint_t);
+       virtual ld::Atom::SymbolTableInclusion  symbolTableInclusion()                  { return ld::Atom::symbolTableIn; }
+       virtual pint_t                                  elementSizeAtAddress(pint_t addr);
+       virtual ld::Atom::Combine               combine(Parser<A>&, pint_t)                             { return ld::Atom::combineNever; }
+       virtual bool                                    ignoreLabel(const char* label)                  { return true; }
+       virtual unsigned long                   contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const
+                                                                                                                                                       { return 0; }
+       virtual bool                                    canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs, 
+                                                                                                       const ld::IndirectBindingTable& ind) const { return false; }
+       virtual bool                                    addRelocFixup(class Parser<A>& parser, const macho_relocation_info<P>*);
+};
+
+
+template <typename A>
+class ObjC2ClassRefsSection : public FixedSizeSection<A>
+{
+public:
+                                               ObjC2ClassRefsSection(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
+                                                       : FixedSizeSection<A>(parser, f, s) {}
+protected:
+       typedef typename A::P::uint_t   pint_t;
+
+       virtual ld::Atom::Alignment             alignmentForAddress(pint_t addr)                { return ld::Atom::Alignment(log2(sizeof(pint_t))); }
+       virtual const char*                             unlabeledAtomName(Parser<A>&, pint_t)   { return "objc-class-ref"; }
+       virtual pint_t                                  elementSizeAtAddress(pint_t addr)               { return sizeof(pint_t); }
+       virtual ld::Atom::Combine               combine(Parser<A>&, pint_t)                             { return ld::Atom::combineByNameAndReferences; }
+       virtual bool                                    ignoreLabel(const char* label)                  { return true; }
+       virtual unsigned long                   contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
+       virtual bool                                    canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs, 
+                                                                                                       const ld::IndirectBindingTable& ind) const;
+private:
+       const char*                                             targetClassName(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
+};
+
+
+template <typename A>
+class ObjC2CategoryListSection : public FixedSizeSection<A>
+{
+public:
+                                               ObjC2CategoryListSection(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
+                                                       : FixedSizeSection<A>(parser, f, s) {}
+protected:
+       typedef typename A::P::uint_t   pint_t;
+
+       virtual ld::Atom::Alignment             alignmentForAddress(pint_t addr)                { return ld::Atom::Alignment(log2(sizeof(pint_t))); }
+       virtual ld::Atom::Scope                 scopeAtAddress(Parser<A>& parser, pint_t addr) { return ld::Atom::scopeTranslationUnit; }
+       virtual const char*                             unlabeledAtomName(Parser<A>&, pint_t)   { return "objc-cat-list"; }
+       virtual pint_t                                  elementSizeAtAddress(pint_t addr)               { return sizeof(pint_t); }
+       virtual ld::Atom::Combine               combine(Parser<A>&, pint_t)                             { return ld::Atom::combineNever; }
+       virtual bool                                    ignoreLabel(const char* label)                  { return true; }
+private:
+       const char*                                             targetClassName(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
+};
+
+
+template <typename A>
+class PointerToCStringSection : public FixedSizeSection<A>
+{
+public:
+                                               PointerToCStringSection(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
+                                                       : FixedSizeSection<A>(parser, f, s) {}
+protected:
+       typedef typename A::P::uint_t   pint_t;
+
+       virtual ld::Atom::Alignment             alignmentForAddress(pint_t addr)                { return ld::Atom::Alignment(log2(sizeof(pint_t))); }
+       virtual const char*                             unlabeledAtomName(Parser<A>&, pint_t)   { return "pointer-to-literal-cstring"; }
+       virtual pint_t                                  elementSizeAtAddress(pint_t addr)               { return sizeof(pint_t); }
+       virtual ld::Atom::Combine               combine(Parser<A>&, pint_t)                             { return ld::Atom::combineByNameAndReferences; }
+       virtual bool                                    ignoreLabel(const char* label)                  { return true; }
+       virtual unsigned long                   contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
+       virtual bool                                    canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs, 
+                                                                                                       const ld::IndirectBindingTable& ind) const;
+       virtual const char*                             targetCString(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
+};
+
+
+template <typename A>
+class Objc1ClassReferences : public PointerToCStringSection<A>
+{
+public:
+                                               Objc1ClassReferences(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
+                                                       : PointerToCStringSection<A>(parser, f, s) {}
+
+       typedef typename A::P::uint_t   pint_t;
+       typedef typename A::P                   P;
+
+       virtual const char*                             unlabeledAtomName(Parser<A>&, pint_t)   { return "pointer-to-literal-objc-class-name"; }
+       virtual bool                                    addRelocFixup(class Parser<A>& parser, const macho_relocation_info<P>*);
+       virtual const char*                             targetCString(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
+};
+
+
+template <typename A>
+class CStringSection : public ImplicitSizeSection<A>
+{
+public:
+                                               CStringSection(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
+                                                       : ImplicitSizeSection<A>(parser, f, s) {}
+protected:
+       typedef typename A::P::uint_t   pint_t;
+       typedef typename A::P                   P;
+
+       virtual ld::Atom::ContentType   contentType()                                                   { return ld::Atom::typeCString; }
+       virtual Atom<A>*                                findAtomByAddress(pint_t addr);
+       virtual const char*                             unlabeledAtomName(Parser<A>&, pint_t)   { return "cstring"; }
+       virtual pint_t                                  elementSizeAtAddress(pint_t addr);
+       virtual bool                                    useElementAt(Parser<A>& parser, 
+                                                                                               struct Parser<A>::LabelAndCFIBreakIterator& it, pint_t addr);
+       virtual ld::Atom::Combine               combine(Parser<A>&, pint_t)                             { return ld::Atom::combineByNameAndContent; }
+       virtual unsigned long                   contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
+       virtual bool                                    canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs, 
+                                                                                                       const ld::IndirectBindingTable& ind) const;
+
+};
+
+
+template <typename A>
+class UTF16StringSection : public SymboledSection<A>
+{
+public:
+                                               UTF16StringSection(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
+                                                       : SymboledSection<A>(parser, f, s) {}
+protected:
+       typedef typename A::P::uint_t   pint_t;
+       typedef typename A::P                   P;
+
+       virtual ld::Atom::Combine               combine(Parser<A>&, pint_t)                             { return ld::Atom::combineByNameAndContent; }
+       virtual unsigned long                   contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
+       virtual bool                                    canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs, 
+                                                                                                       const ld::IndirectBindingTable& ind) const;
+};
+
+
+//
+// Atoms in mach-o files
+//
+template <typename A>
+class Atom : public ld::Atom
+{
+public:
+       // overrides of ld::Atom
+       virtual ld::File*                                                       file() const            { return &sect().file(); }
+       virtual bool                                                            translationUnitSource(const char** dir, const char** nm) const
+                                                                                                                                       { return sect().file().translationUnitSource(dir, nm); }
+       virtual const char*                                                     name() const            { return _name; }
+       virtual uint64_t                                                        size() const            { return _size; }
+       virtual uint64_t                                                        objectAddress() const { return _objAddress; }
+       virtual void                                                            copyRawContent(uint8_t buffer[]) const;
+       virtual const uint8_t*                                          rawContentPointer() const { return contentPointer(); }
+       virtual unsigned long                                           contentHash(const ld::IndirectBindingTable& ind) const 
+                                                                                                                       { if ( _hash == 0 ) _hash = sect().contentHash(this, ind); return _hash; }
+       virtual bool                                                            canCoalesceWith(const ld::Atom& rhs, const ld::IndirectBindingTable& ind) const 
+                                                                                                                       { return sect().canCoalesceWith(this, rhs, ind); }
+       virtual ld::Fixup::iterator                                     fixupsBegin() const     { return &machofile()._fixups[_fixupsStartIndex]; }
+       virtual ld::Fixup::iterator                                     fixupsEnd()     const   { return &machofile()._fixups[_fixupsStartIndex+_fixupsCount]; }
+       virtual ld::Atom::UnwindInfo::iterator          beginUnwind() const     { return &machofile()._unwindInfos[_unwindInfoStartIndex]; }
+       virtual ld::Atom::UnwindInfo::iterator          endUnwind()     const   { return &machofile()._unwindInfos[_unwindInfoStartIndex+_unwindInfoCount];  }
+       virtual ld::Atom::LineInfo::iterator            beginLineInfo() const{ return &machofile()._lineInfos[_lineInfoStartIndex]; }
+       virtual ld::Atom::LineInfo::iterator            endLineInfo() const { return &machofile()._lineInfos[_lineInfoStartIndex+_lineInfoCount];  }
+
+private:
+
+       enum {  kFixupStartIndexBits = 32,
+                       kLineInfoStartIndexBits = 32, 
+                       kUnwindInfoStartIndexBits = 24,
+                       kFixupCountBits = 24, 
+                       kLineInfoCountBits = 12,
+                       kUnwindInfoCountBits = 4
+               }; // must sum to 128
+
+public:
+       // methods for all atoms from mach-o object file
+                       Section<A>&                                                     sect() const                    { return (Section<A>&)section(); }
+                       File<A>&                                                        machofile() const                       { return ((Section<A>*)(this->_section))->file(); }
+                       void                                                            setFixupsRange(uint32_t s, uint32_t c);
+                       void                                                            setUnwindInfoRange(uint32_t s, uint32_t c);
+                       void                                                            setLineInfoRange(uint32_t s, uint32_t c);
+                       bool                                                            roomForMoreLineInfoCount() { return (_lineInfoCount < ((1<<kLineInfoCountBits)-1)); }
+                       void                                                            incrementLineInfoCount() { assert(roomForMoreLineInfoCount()); ++_lineInfoCount; }
+                       void                                                            incrementFixupCount() { if (_fixupsCount == ((1 << kFixupCountBits)-1)) 
+                                                                                                                                                       throwf("too may fixups in %s", name()); ++_fixupsCount; }
+                       const uint8_t*                                          contentPointer() const;
+                       uint32_t                                                        fixupCount() const { return _fixupsCount; }
+                       void                                                            verifyAlignment() const;
+       
+       typedef typename A::P                                           P;
+       typedef typename A::P::E                                        E;
+       typedef typename A::P::uint_t                           pint_t;
+                                                                                               // constuct via all attributes
+                                                                                               Atom(Section<A>& sct, const char* nm, pint_t addr, uint64_t sz, 
+                                                                                                       ld::Atom::Definition d, ld::Atom::Combine c, ld::Atom::Scope s, 
+                                                                                                       ld::Atom::ContentType ct, ld::Atom::SymbolTableInclusion i, 
+                                                                                                       bool dds, bool thumb, bool al, ld::Atom::Alignment a) 
+                                                                                                               : ld::Atom((ld::Section&)sct, d, c, s, ct, i, dds, thumb, al, a), 
+                                                                                                                       _size(sz), _objAddress(addr), _name(nm), _hash(0), 
+                                                                                                                       _fixupsStartIndex(0), _lineInfoStartIndex(0),
+                                                                                                                       _unwindInfoStartIndex(0), _fixupsCount(0),  
+                                                                                                                       _lineInfoCount(0), _unwindInfoCount(0) { }
+                                                                                               // construct via symbol table entry
+                                                                                               Atom(Section<A>& sct, Parser<A>& parser, const macho_nlist<P>& sym, 
+                                                                                                                               uint64_t sz, bool alias=false)
+                                                                                                               : ld::Atom((ld::Section&)sct, parser.definitionFromSymbol(sym), 
+                                                                                                                               parser.combineFromSymbol(sym), parser.scopeFromSymbol(sym),
+                                                                                                                               parser.resolverFromSymbol(sym) ? ld::Atom::typeResolver : sct.contentType(), 
+                                                                                                                               parser.inclusionFromSymbol(sym), 
+                                                                                                                               parser.dontDeadStripFromSymbol(sym) || sct.dontDeadStrip(),
+                                                                                                                               parser.isThumbFromSymbol(sym), alias, 
+                                                                                                                               sct.alignmentForAddress(sym.n_value())),
+                                                                                                                       _size(sz), _objAddress(sym.n_value()), 
+                                                                                                                       _name(parser.nameFromSymbol(sym)), _hash(0), 
+                                                                                                                       _fixupsStartIndex(0), _lineInfoStartIndex(0),
+                                                                                                                       _unwindInfoStartIndex(0), _fixupsCount(0),  
+                                                                                                                       _lineInfoCount(0), _unwindInfoCount(0) { 
+                                                                                                                               // <rdar://problem/6783167> support auto-hidden weak symbols
+                                                                                                                               if ( _scope == ld::Atom::scopeGlobal && 
+                                                                                                                                               (sym.n_desc() & (N_WEAK_DEF|N_WEAK_REF)) == (N_WEAK_DEF|N_WEAK_REF) )
+                                                                                                                                       this->setAutoHide();
+                                                                                                                                       this->verifyAlignment();
+                                                                                                                       }
+
+private:
+       friend class Parser<A>;
+       friend class Section<A>;
+       friend class CStringSection<A>;
+       friend class AbsoluteSymbolSection<A>;
+       
+       pint_t                                                                          _size;
+       pint_t                                                                          _objAddress;
+       const char*                                                                     _name;
+       mutable unsigned long                                           _hash;
+
+       uint64_t                                                                        _fixupsStartIndex               : kFixupStartIndexBits,
+                                                                                               _lineInfoStartIndex             : kLineInfoStartIndexBits,                      
+                                                                                               _unwindInfoStartIndex   : kUnwindInfoStartIndexBits,
+                                                                                               _fixupsCount                    : kFixupCountBits,
+                                                                                               _lineInfoCount                  : kLineInfoCountBits,
+                                                                                               _unwindInfoCount                : kUnwindInfoCountBits;
+
+};
+
+
+
+template <typename A>
+void Atom<A>::setFixupsRange(uint32_t startIndex, uint32_t count)
+{ 
+       if ( count >= (1 << kFixupCountBits) ) 
+               throwf("too many fixups in function %s", this->name());
+       if ( startIndex >= (1 << kFixupStartIndexBits) ) 
+               throwf("too many fixups in file");
+       assert(((startIndex+count) <= sect().file()._fixups.size()) && "fixup index out of range");
+       _fixupsStartIndex = startIndex; 
+       _fixupsCount = count; 
+}
+
+template <typename A>
+void Atom<A>::setUnwindInfoRange(uint32_t startIndex, uint32_t count)
+{
+       if ( count >= (1 << kUnwindInfoCountBits) ) 
+               throwf("too many compact unwind infos in function %s", this->name());
+       if ( startIndex >= (1 << kUnwindInfoStartIndexBits) ) 
+               throwf("too many compact unwind infos (%d) in file", startIndex);
+       assert((startIndex+count) <= sect().file()._unwindInfos.size() && "unwindinfo index out of range");
+       _unwindInfoStartIndex = startIndex; 
+       _unwindInfoCount = count; 
+}
+
+template <typename A>
+void Atom<A>::setLineInfoRange(uint32_t startIndex, uint32_t count)
+{ 
+       assert((count < (1 << kLineInfoCountBits)) && "too many line infos");
+       assert((startIndex+count) < sect().file()._lineInfos.size() && "line info index out of range");
+       _lineInfoStartIndex = startIndex; 
+       _lineInfoCount = count; 
+}
+
+template <typename A>
+const uint8_t* Atom<A>::contentPointer() const
+{
+       const macho_section<P>* sct = this->sect().machoSection();
+       uint32_t fileOffset = sct->offset() - sct->addr() + this->_objAddress;
+       return this->sect().file().fileContent()+fileOffset;
+}
+
+
+template <typename A>
+void Atom<A>::copyRawContent(uint8_t buffer[]) const
+{
+       // copy base bytes
+       if ( this->contentType() == ld::Atom::typeZeroFill ) {
+               bzero(buffer, _size);
+       }
+       else if ( _size != 0 ) {
+               memcpy(buffer, this->contentPointer(), _size);
+       }
+}
+
+template <>
+void Atom<arm>::verifyAlignment() const
+{
+       if ( (this->section().type() == ld::Section::typeCode) && ! isThumb() ) {
+               if ( (_objAddress % 4) != 0 )
+                       warning("ARM function %s not 4-byte aligned", this->name());
+       }
+}
+
+template <typename A>
+void Atom<A>::verifyAlignment() const
+{
+}
+
+
+template <typename A>
+class Parser 
+{
+public:
+       static bool                                                                             validFile(const uint8_t* fileContent, bool subtypeMustMatch=false, 
+                                                                                                                               cpu_subtype_t subtype=0);
+       static const char*                                                              fileKind(const uint8_t* fileContent);
+       static bool                                                                             hasObjC2Categories(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 ParserOptions& opts) {
+                                                                                                                               Parser p(fileContent, fileLength, path, modTime, 
+                                                                                                                                               ordinal, opts.convertUnwindInfo);
+                                                                                                                               return p.parse(opts);
+                                                                                                               }
+
+       typedef typename A::P                                           P;
+       typedef typename A::P::E                                        E;
+       typedef typename A::P::uint_t                           pint_t;
+
+       struct SourceLocation {
+                                                               SourceLocation() {}
+                                                               SourceLocation(Atom<A>* a, uint32_t o) : atom(a), offsetInAtom(o) {}
+               Atom<A>*        atom;
+               uint32_t        offsetInAtom;
+       };
+
+       struct TargetDesc {
+               Atom<A>*        atom;           
+               const char*     name;           // only used if targetAtom is NULL
+               int64_t         addend;
+               bool            weakImport;     // only used if targetAtom is NULL
+       };
+
+       struct FixupInAtom {
+               FixupInAtom(const SourceLocation& src, ld::Fixup::Cluster c, ld::Fixup::Kind k, Atom<A>* target) :
+                       fixup(src.offsetInAtom, c, k, target), atom(src.atom) { src.atom->incrementFixupCount(); }
+                       
+               FixupInAtom(const SourceLocation& src, ld::Fixup::Cluster c, ld::Fixup::Kind k, ld::Fixup::TargetBinding b, Atom<A>* target) :
+                       fixup(src.offsetInAtom, c, k, b, target), atom(src.atom) { src.atom->incrementFixupCount(); }
+                       
+               FixupInAtom(const SourceLocation& src, ld::Fixup::Cluster c, ld::Fixup::Kind k, bool wi, const char* name) :
+                       fixup(src.offsetInAtom, c, k, wi, name), atom(src.atom) { src.atom->incrementFixupCount(); }
+                                       
+               FixupInAtom(const SourceLocation& src, ld::Fixup::Cluster c, ld::Fixup::Kind k, ld::Fixup::TargetBinding b, const char* name) :
+                       fixup(src.offsetInAtom, c, k, b, name), atom(src.atom) { src.atom->incrementFixupCount(); }
+                                       
+               FixupInAtom(const SourceLocation& src, ld::Fixup::Cluster c, ld::Fixup::Kind k, uint64_t addend) :
+                       fixup(src.offsetInAtom, c, k, addend), atom(src.atom) { src.atom->incrementFixupCount(); }
+
+               FixupInAtom(const SourceLocation& src, ld::Fixup::Cluster c, ld::Fixup::Kind k) :
+                       fixup(src.offsetInAtom, c, k, (uint64_t)0), atom(src.atom) { src.atom->incrementFixupCount(); }
+
+               ld::Fixup               fixup;
+               Atom<A>*                atom;
+       };
+
+       void addFixup(const SourceLocation& src, ld::Fixup::Cluster c, ld::Fixup::Kind k, Atom<A>* target) { 
+               _allFixups.push_back(FixupInAtom(src, c, k, target)); 
+       }
+       
+       void addFixup(const SourceLocation& src, ld::Fixup::Cluster c, ld::Fixup::Kind k, ld::Fixup::TargetBinding b, Atom<A>* target) { 
+               _allFixups.push_back(FixupInAtom(src, c, k, b, target)); 
+       }
+       
+       void addFixup(const SourceLocation& src, ld::Fixup::Cluster c, ld::Fixup::Kind k, bool wi, const char* name) { 
+               _allFixups.push_back(FixupInAtom(src, c, k, wi, name)); 
+       }
+       
+       void addFixup(const SourceLocation& src, ld::Fixup::Cluster c, ld::Fixup::Kind k, ld::Fixup::TargetBinding b, const char* name) { 
+               _allFixups.push_back(FixupInAtom(src, c, k, b, name)); 
+       }
+       
+       void addFixup(const SourceLocation& src, ld::Fixup::Cluster c, ld::Fixup::Kind k, uint64_t addend) { 
+               _allFixups.push_back(FixupInAtom(src, c, k, addend)); 
+       }
+
+       void addFixup(const SourceLocation& src, ld::Fixup::Cluster c, ld::Fixup::Kind k) { 
+               _allFixups.push_back(FixupInAtom(src, c, k)); 
+       }
+
+
+       uint32_t                                                                                symbolCount() { return _symbolCount; }
+       uint32_t                                                                                indirectSymbol(uint32_t indirectIndex);
+       const macho_nlist<P>&                                                   symbolFromIndex(uint32_t index);
+       const char*                                                                             nameFromSymbol(const macho_nlist<P>& sym);
+       ld::Atom::Scope                                                                 scopeFromSymbol(const macho_nlist<P>& sym);
+       static ld::Atom::Definition                                             definitionFromSymbol(const macho_nlist<P>& sym);
+       static ld::Atom::Combine                                                combineFromSymbol(const macho_nlist<P>& sym);
+                       ld::Atom::SymbolTableInclusion                  inclusionFromSymbol(const macho_nlist<P>& sym);
+       static bool                                                                             dontDeadStripFromSymbol(const macho_nlist<P>& sym);
+       static bool                                                                             isThumbFromSymbol(const macho_nlist<P>& sym);
+       static bool                                                                             weakImportFromSymbol(const macho_nlist<P>& sym);
+       static bool                                                                             resolverFromSymbol(const macho_nlist<P>& sym);
+       uint32_t                                                                                symbolIndexFromIndirectSectionAddress(pint_t,const macho_section<P>*);
+       const macho_section<P>*                                                 firstMachOSection() { return _sectionsStart; }
+       const macho_section<P>*                                                 machOSectionFromSectionIndex(uint32_t index);
+       uint32_t                                                                                machOSectionCount() { return _machOSectionsCount; }
+       uint32_t                                                                                undefinedStartIndex() { return _undefinedStartIndex; }
+       uint32_t                                                                                undefinedEndIndex() { return _undefinedEndIndex; }
+       void                                                                                    addFixup(FixupInAtom f) { _allFixups.push_back(f); }
+       Section<A>*                                                                             sectionForNum(unsigned int sectNum);
+       Section<A>*                                                                             sectionForAddress(pint_t addr);
+       Atom<A>*                                                                                findAtomByAddress(pint_t addr);
+       Atom<A>*                                                                                findAtomByAddressOrNullIfStub(pint_t addr);
+       Atom<A>*                                                                                findAtomByAddressOrLocalTargetOfStub(pint_t addr, uint32_t* offsetInAtom);
+       Atom<A>*                                                                                findAtomByName(const char* name);       // slow!
+       void                                                                                    findTargetFromAddress(pint_t addr, TargetDesc& target);
+       void                                                                                    findTargetFromAddress(pint_t baseAddr, pint_t addr, TargetDesc& target);
+       void                                                                                    findTargetFromAddressAndSectionNum(pint_t addr, unsigned int sectNum,
+                                                                                                                                                                               TargetDesc& target);
+       uint32_t                                                                                tentativeDefinitionCount() { return _tentativeDefinitionCount; }
+       uint32_t                                                                                absoluteSymbolCount() { return _absoluteSymbolCount; }
+       
+       bool                                                                                    hasStubsSection() { return (_stubsSectionNum != 0); }
+       unsigned int                                                                    stubsSectionNum() { return _stubsSectionNum; }
+       void                                                                                    addDtraceExtraInfos(const SourceLocation& src, const char* provider);
+       const char*                                                                             scanSymbolTableForAddress(uint64_t addr);
+       bool                                                                                    convertUnwindInfo() { return _convertUnwindInfo; }
+
+       
+       void                                                    addFixups(const SourceLocation& src, ld::Fixup::Kind kind, const TargetDesc& target);
+       void                                                    addFixups(const SourceLocation& src, ld::Fixup::Kind kind, const TargetDesc& target, const TargetDesc& picBase);
+       
+
+
+       struct LabelAndCFIBreakIterator {
+               typedef typename CFISection<A>::CFI_Atom_Info CFI_Atom_Info;
+                                                               LabelAndCFIBreakIterator(const uint32_t* ssa, uint32_t ssc, const pint_t* cfisa, 
+                                                                                                               uint32_t cfisc, bool ols)
+                                                                       : sortedSymbolIndexes(ssa), sortedSymbolCount(ssc), cfiStartsArray(cfisa), 
+                                                                               cfiStartsCount(cfisc), fileHasOverlappingSymbols(ols),
+                                                                               newSection(false), cfiIndex(0), symIndex(0) {}
+               bool                                    next(Parser<A>& parser, uint32_t sectNum, pint_t startAddr, pint_t endAddr, 
+                                                                               pint_t* addr, pint_t* size, const macho_nlist<P>** sym);
+               pint_t                                  peek(Parser<A>& parser, pint_t startAddr, pint_t endAddr);
+               void                                    beginSection() { newSection = true; symIndex = 0; }
+               
+               const uint32_t* const           sortedSymbolIndexes;
+               const uint32_t                          sortedSymbolCount;
+               const pint_t*                           cfiStartsArray;
+               const uint32_t                          cfiStartsCount;
+               const bool                                      fileHasOverlappingSymbols;
+               bool                                            newSection;
+               uint32_t                                        cfiIndex;
+               uint32_t                                        symIndex;
+       };
+
+       struct CFIInfoArray {
+                       typedef typename CFISection<A>::CFI_Atom_Info CFI_Atom_Info;
+                                                       CFIInfoArray(const CFI_Atom_Info* cfia, uint32_t cfiac) : array(cfia), count(cfiac) {} 
+               const CFI_Atom_Info* const      array;
+               const uint32_t                          count;
+       };
+
+
+private:
+       friend class Section<A>;
+       
+       enum SectionType { sectionTypeIgnore, sectionTypeLiteral4, sectionTypeLiteral8, sectionTypeLiteral16, 
+                                               sectionTypeNonLazy, sectionTypeCFI, sectionTypeCString, sectionTypeCStringPointer, 
+                                               sectionTypeUTF16Strings, sectionTypeCFString, sectionTypeObjC2ClassRefs, typeObjC2CategoryList,
+                                               sectionTypeObjC1Classes, sectionTypeSymboled, sectionTypeObjC1ClassRefs,
+                                               sectionTypeTentativeDefinitions, sectionTypeAbsoluteSymbols, sectionTypeTLVDefs };
+
+       template <typename P>
+       struct MachOSectionAndSectionClass
+       {
+               const macho_section<P>* sect;
+               SectionType                             type;
+               
+               static int sorter(const void* l, const void* r) {
+                       const MachOSectionAndSectionClass<P>* left = (MachOSectionAndSectionClass<P>*)l;
+                       const MachOSectionAndSectionClass<P>* right = (MachOSectionAndSectionClass<P>*)r;
+                       int64_t diff = left->sect->addr() - right->sect->addr();
+                       if ( diff == 0 )
+                               return 0;
+                       if ( diff < 0 )
+                               return -1;
+                       else
+                               return 1;
+               }
+       };
+
+                                                                                                       Parser(const uint8_t* fileContent, uint64_t fileLength, 
+                                                                                                                       const char* path, time_t modTime, 
+                                                                                                                       uint32_t ordinal, bool convertUnwindInfo);
+       ld::relocatable::File*                                                  parse(const ParserOptions& opts);
+       uint8_t                                                                                 loadCommandSizeMask();
+       bool                                                                                    parseLoadCommands();
+       void                                                                                    makeSections();
+       void                                                                                    checkForLSDA();
+       void                                                                                    prescanSymbolTable();
+       void                                                                                    makeSortedSymbolsArray(uint32_t array[]);
+       static int                                                                              pointerSorter(const void* l, const void* r);
+       static int                                                                              symbolIndexSorter(void* extra, const void* l, const void* r);
+       void                                                                                    parseDebugInfo();
+       void                                                                                    parseStabs();
+       static bool                                                                             isConstFunStabs(const char *stabStr);
+       bool                                                                                    read_comp_unit(const char ** name, const char ** comp_dir,
+                                                                                                                                                                                               uint64_t *stmt_list);
+       const char*                                                                             getDwarfString(uint64_t form, const uint8_t* p);
+       bool                                                                                    skip_form(const uint8_t ** offset, const uint8_t * end, 
+                                                                                                                               uint64_t form, uint8_t addr_size, bool dwarf64);
+       
+
+       // filled in by constructor
+       const uint8_t*                                                          _fileContent;
+       uint32_t                                                                        _fileLength;
+       const char*                                                                     _path;
+       time_t                                                                          _modTime;
+       uint32_t                                                                        _ordinal;
+       
+       // filled in by parseLoadCommands()
+       File<A>*                                                                        _file;
+       const macho_nlist<P>*                                           _symbols;
+       uint32_t                                                                        _symbolCount;
+       const char*                                                                     _strings;
+       uint32_t                                                                        _stringsSize;
+       const uint32_t*                                                         _indirectTable;
+       uint32_t                                                                        _indirectTableCount;
+       uint32_t                                                                        _undefinedStartIndex;
+       uint32_t                                                                        _undefinedEndIndex;
+       const macho_section<P>*                                         _sectionsStart;
+       uint32_t                                                                        _machOSectionsCount;
+       bool                                                                            _hasUUID;
+       
+       // filled in by parse()
+       CFISection<A>*                                                          _EHFrameSection;
+       AbsoluteSymbolSection<A>*                                       _absoluteSection;
+       uint32_t                                                                        _lsdaTextSectionNum;
+       uint32_t                                                                        _lsdaDataSectionNum;
+       uint32_t                                                                        _tentativeDefinitionCount;
+       uint32_t                                                                        _absoluteSymbolCount;
+       uint32_t                                                                        _symbolsInSections;
+       bool                                                                            _hasLongBranchStubs;
+       bool                                                                            _AppleObjc; // FSF has objc that uses different data layout
+       bool                                                                            _overlappingSymbols;
+       bool                                                                            _convertUnwindInfo;
+       unsigned int                                                            _stubsSectionNum;
+       const macho_section<P>*                                         _stubsMachOSection;
+       std::vector<const char*>                                        _dtraceProviderInfo;
+       std::vector<FixupInAtom>                                        _allFixups;
+};
+
+
+
+template <typename A>
+Parser<A>::Parser(const uint8_t* fileContent, uint64_t fileLength, const char* path, time_t modTime, 
+                                       uint32_t ordinal, bool convertDUI)
+               : _fileContent(fileContent), _fileLength(fileLength), _path(path), _modTime(modTime),
+                       _ordinal(ordinal), _file(NULL),
+                       _symbols(NULL), _symbolCount(0), _strings(NULL), _stringsSize(0),
+                       _indirectTable(NULL), _indirectTableCount(0), 
+                       _undefinedStartIndex(0), _undefinedEndIndex(0), 
+                       _sectionsStart(NULL), _machOSectionsCount(0), _hasUUID(false), 
+                       _EHFrameSection(NULL), _absoluteSection(NULL),
+                       _lsdaTextSectionNum(0), _lsdaDataSectionNum(0),
+                       _tentativeDefinitionCount(0), _absoluteSymbolCount(0),
+                       _symbolsInSections(0), _hasLongBranchStubs(false),  _AppleObjc(false),
+                       _overlappingSymbols(false), _convertUnwindInfo(convertDUI), 
+                       _stubsSectionNum(0), _stubsMachOSection(NULL)
+{
+}
+
+template <>
+bool Parser<ppc>::validFile(const uint8_t* fileContent, bool, cpu_subtype_t)
+{
+       const macho_header<P>* header = (const macho_header<P>*)fileContent;
+       if ( header->magic() != MH_MAGIC )
+               return false;
+       if ( header->cputype() != CPU_TYPE_POWERPC )
+               return false;
+       if ( header->filetype() != MH_OBJECT )
+               return false;
+       return true;
+}
+
+template <>
+bool Parser<ppc64>::validFile(const uint8_t* fileContent, bool, cpu_subtype_t)
+{
+       const macho_header<P>* header = (const macho_header<P>*)fileContent;
+       if ( header->magic() != MH_MAGIC_64 )
+               return false;
+       if ( header->cputype() != CPU_TYPE_POWERPC64 )
+               return false;
+       if ( header->filetype() != MH_OBJECT )
+               return false;
+       return true;
+}
+
+template <>
+bool Parser<x86>::validFile(const uint8_t* fileContent, bool, cpu_subtype_t)
+{
+       const macho_header<P>* header = (const macho_header<P>*)fileContent;
+       if ( header->magic() != MH_MAGIC )
+               return false;
+       if ( header->cputype() != CPU_TYPE_I386 )
+               return false;
+       if ( header->filetype() != MH_OBJECT )
+               return false;
+       return true;
+}
+
+template <>
+bool Parser<x86_64>::validFile(const uint8_t* fileContent, bool, cpu_subtype_t)
+{
+       const macho_header<P>* header = (const macho_header<P>*)fileContent;
+       if ( header->magic() != MH_MAGIC_64 )
+               return false;
+       if ( header->cputype() != CPU_TYPE_X86_64 )
+               return false;
+       if ( header->filetype() != MH_OBJECT )
+               return false;
+       return true;
+}
+
+template <>
+bool Parser<arm>::validFile(const uint8_t* fileContent, bool subtypeMustMatch, cpu_subtype_t subtype)
+{
+       const macho_header<P>* header = (const macho_header<P>*)fileContent;
+       if ( header->magic() != MH_MAGIC )
+               return false;
+       if ( header->cputype() != CPU_TYPE_ARM )
+               return false;
+       if ( header->filetype() != MH_OBJECT )
+               return false;
+       if ( subtypeMustMatch ) {
+               if ( (cpu_subtype_t)header->cpusubtype() == subtype )
+                       return true;
+               // hack until libcc_kext.a is made fat
+               if ( header->cpusubtype() == CPU_SUBTYPE_ARM_ALL )
+                       return true;
+               return false;
+       }
+       return true;
+}
+
+
+template <>
+const char* Parser<ppc>::fileKind(const uint8_t* fileContent)
+{
+       const macho_header<P>* header = (const macho_header<P>*)fileContent;
+       if ( header->magic() != MH_MAGIC )
+               return NULL;
+       if ( header->cputype() != CPU_TYPE_POWERPC )
+               return NULL;
+       switch ( header->cpusubtype() ) {
+               case CPU_SUBTYPE_POWERPC_750:
+                       return "ppc750";
+               case CPU_SUBTYPE_POWERPC_7400:
+                       return "ppc7400";
+               case CPU_SUBTYPE_POWERPC_7450:
+                       return "ppc7450";
+               case CPU_SUBTYPE_POWERPC_970:
+                       return "ppc970";
+               case CPU_SUBTYPE_POWERPC_ALL:
+                       return "ppc";
+       }
+       return "ppc???";
+}
+
+template <>
+const char* Parser<ppc64>::fileKind(const uint8_t* fileContent)
+{
+       const macho_header<P>* header = (const macho_header<P>*)fileContent;
+       if ( header->magic() != MH_MAGIC )
+               return NULL;
+       if ( header->cputype() != CPU_TYPE_POWERPC64 )
+               return NULL;
+       return "ppc64";
+}
+
+template <>
+const char* Parser<x86>::fileKind(const uint8_t* fileContent)
+{
+       const macho_header<P>* header = (const macho_header<P>*)fileContent;
+       if ( header->magic() != MH_MAGIC )
+               return NULL;
+       if ( header->cputype() != CPU_TYPE_I386 )
+               return NULL;
+       return "i386";
+}
+
+template <>
+const char* Parser<x86_64>::fileKind(const uint8_t* fileContent)
+{
+       const macho_header<P>* header = (const macho_header<P>*)fileContent;
+       if ( header->magic() != MH_MAGIC )
+               return NULL;
+       if ( header->cputype() != CPU_TYPE_X86_64 )
+               return NULL;
+       return "x86_64";
+}
+
+template <>
+const char* Parser<arm>::fileKind(const uint8_t* fileContent)
+{
+       const macho_header<P>* header = (const macho_header<P>*)fileContent;
+       if ( header->magic() != MH_MAGIC )
+               return NULL;
+       if ( header->cputype() != CPU_TYPE_ARM )
+               return NULL;
+       switch ( header->cpusubtype() ) {
+               case CPU_SUBTYPE_ARM_V4T:
+                       return "armv4t";
+               case CPU_SUBTYPE_ARM_V5TEJ:
+                       return "armv5";
+               case CPU_SUBTYPE_ARM_V6:
+                       return "armv6";
+               case CPU_SUBTYPE_ARM_V7:
+                       return "armv7";
+               case CPU_SUBTYPE_ARM_ALL:
+                       return "arm-ALL";
+       }
+       return "arm???";
+}
+
+
+template <typename A>
+bool Parser<A>::hasObjC2Categories(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(), "__objc_catlist") == 0)
+                                       && (strcmp(sect->segname(), "__DATA") == 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)
+{
+       // sort references by address 
+       const pint_t* left = (pint_t*)l;
+       const pint_t* right = (pint_t*)r;
+       return (*left - *right);
+}
+
+template <typename A>
+typename A::P::uint_t Parser<A>::LabelAndCFIBreakIterator::peek(Parser<A>& parser, pint_t startAddr, pint_t endAddr)
+{
+       pint_t symbolAddr;
+       if ( symIndex < sortedSymbolCount )
+               symbolAddr = parser.symbolFromIndex(sortedSymbolIndexes[symIndex]).n_value();
+       else
+               symbolAddr = endAddr;
+       pint_t cfiAddr;
+       if ( cfiIndex < cfiStartsCount )
+               cfiAddr = cfiStartsArray[cfiIndex];
+       else
+               cfiAddr = endAddr;
+       if ( (cfiAddr < symbolAddr) && (cfiAddr >= startAddr) ) {
+               if ( cfiAddr <  endAddr )
+                       return cfiAddr;
+               else
+                       return endAddr;         
+       }
+       else  {
+               if ( symbolAddr <  endAddr )
+                       return symbolAddr;
+               else
+                       return endAddr;
+       }
+}
+
+//
+// Parses up a section into chunks based on labels and CFI information.
+// Each call returns the next chunk address and size, and (if the break
+// was becuase of a label, the symbol). Returns false when no more chunks.
+//
+template <typename A>
+bool Parser<A>::LabelAndCFIBreakIterator::next(Parser<A>& parser, uint32_t sectNum, pint_t startAddr, pint_t endAddr, 
+                                                                                               pint_t* addr, pint_t* size, const macho_nlist<P>** symbol)
+{
+       // may not be a label on start of section, but need atom demarcation there
+       if ( newSection ) {
+               newSection = false;
+               // advance symIndex until we get to the first label at or past the start of this section
+               while ( symIndex < sortedSymbolCount ) {
+                       const macho_nlist<P>& sym = parser.symbolFromIndex(sortedSymbolIndexes[symIndex]);
+                       pint_t nextSymbolAddr = sym.n_value();
+                       if ( (nextSymbolAddr >= startAddr) && (sym.n_sect() >= sectNum) )
+                               break;
+                       ++symIndex;
+               }
+               if ( symIndex < sortedSymbolCount ) {
+                       const macho_nlist<P>& sym = parser.symbolFromIndex(sortedSymbolIndexes[symIndex]);
+                       pint_t nextSymbolAddr = sym.n_value();
+                       // if next symbol found is not in this section
+                       if ( sym.n_sect() != sectNum ) {
+                               // check for CFI break instead of symbol break
+                               if ( cfiIndex < cfiStartsCount ) {
+                                       pint_t nextCfiAddr = cfiStartsArray[cfiIndex];
+                                       if ( nextCfiAddr < endAddr ) {
+                                               // use cfi
+                                               ++cfiIndex;
+                                               *addr = nextCfiAddr;
+                                               *size = peek(parser, startAddr, endAddr) - nextCfiAddr;
+                                               *symbol = NULL;
+                                               return true;
+                                       }
+                               }
+                               *addr = startAddr;
+                               *size = endAddr - startAddr;
+                               *symbol = NULL;
+                               if ( startAddr == endAddr )
+                                       return false;  // zero size section
+                               else
+                                       return true;  // whole section is one atom with no label
+                       }
+                       // if also CFI break here, eat it
+                       if ( cfiIndex < cfiStartsCount ) {
+                               if ( cfiStartsArray[cfiIndex] == nextSymbolAddr )
+                                       ++cfiIndex;
+                       }
+                       if ( nextSymbolAddr == startAddr ) {
+                               // label at start of section, return it as chunk
+                               ++symIndex;
+                               *addr = startAddr;
+                               *size = peek(parser, startAddr, endAddr) - startAddr;
+                               *symbol = &sym;
+                               return true;
+                       }
+                       // return chunk before first symbol
+                       *addr = startAddr;
+                       *size = nextSymbolAddr - startAddr;
+                       *symbol = NULL;
+                       return true;
+               }
+               // no symbols left in whole file, so entire section is one chunk
+               *addr = startAddr;
+               *size = endAddr - startAddr;
+               *symbol = NULL;
+               if ( startAddr == endAddr )
+                       return false;  // zero size section
+               else
+                       return true;  // whole section is one atom with no label
+       }
+
+       while ( (symIndex < sortedSymbolCount) && (cfiIndex < cfiStartsCount) ) {
+               const macho_nlist<P>& sym = parser.symbolFromIndex(sortedSymbolIndexes[symIndex]);
+               pint_t nextSymbolAddr = sym.n_value();
+               pint_t nextCfiAddr = cfiStartsArray[cfiIndex];
+               if ( nextSymbolAddr <  nextCfiAddr ) {
+                       if ( nextSymbolAddr >= endAddr )
+                               return false;
+                       ++symIndex;
+                       if ( nextSymbolAddr < startAddr )
+                               continue;
+                       *addr = nextSymbolAddr;
+                       *size = peek(parser, startAddr, endAddr) - nextSymbolAddr;
+                       *symbol = &sym;
+                       return true;
+               }
+               else if ( nextCfiAddr < nextSymbolAddr ) { 
+                       if ( nextCfiAddr >= endAddr )
+                               return false;
+                       ++cfiIndex;
+                       if ( nextCfiAddr < startAddr )
+                               continue;
+                       *addr = nextCfiAddr;
+                       *size = peek(parser, startAddr, endAddr) - nextCfiAddr;
+                       *symbol = NULL;
+                       return true;
+               }
+               else {
+                       if ( nextCfiAddr >= endAddr )
+                               return false;
+                       ++symIndex;
+                       ++cfiIndex;
+                       if ( nextCfiAddr < startAddr )
+                               continue;
+                       *addr = nextCfiAddr;
+                       *size = peek(parser, startAddr, endAddr) - nextCfiAddr;
+                       *symbol = &sym;
+                       return true;
+               }
+       }
+       while ( symIndex < sortedSymbolCount ) {
+               const macho_nlist<P>& sym = parser.symbolFromIndex(sortedSymbolIndexes[symIndex]);
+               pint_t nextSymbolAddr = sym.n_value();
+               // if next symbol found is not in this section, then done with iteration
+               if ( sym.n_sect() != sectNum ) 
+                       return false;
+               ++symIndex;
+               if ( nextSymbolAddr < startAddr )
+                       continue;
+               *addr = nextSymbolAddr;
+               *size = peek(parser, startAddr, endAddr) - nextSymbolAddr;
+               *symbol = &sym;
+               return true;
+       }
+       while ( cfiIndex < cfiStartsCount ) {
+               pint_t nextCfiAddr = cfiStartsArray[cfiIndex];
+               if ( nextCfiAddr >= endAddr )
+                       return false;
+               ++cfiIndex;
+               if ( nextCfiAddr < startAddr )
+                       continue;
+               *addr = nextCfiAddr;
+               *size = peek(parser, startAddr, endAddr) - nextCfiAddr;
+               *symbol = NULL;
+               return true;
+       }
+       return false;
+}
+
+
+
+template <typename A>
+ld::relocatable::File* Parser<A>::parse(const ParserOptions& opts)
+{
+       // create file object
+       _file = new File<A>(_path, _modTime, _fileContent, _ordinal);
+
+       // respond to -t option
+       if ( opts.logAllFiles )
+               printf("%s\n", _path);
+
+       // parse start of mach-o file
+       if ( ! parseLoadCommands() )
+               return _file;
+       
+       // make symbol table sorted by address
+       this->checkForLSDA();
+       this->prescanSymbolTable();
+       uint32_t sortedSymbolIndexes[_symbolsInSections];
+       this->makeSortedSymbolsArray(sortedSymbolIndexes);
+               
+       // allocate Section<A> object for each mach-o section
+       makeSections();
+       
+       // if it exists, do special parsing of __eh_frame section 
+       // stack allocate array of CFI_Atom_Info
+       uint32_t countOfCFIs = 0;
+       if ( _EHFrameSection != NULL )
+               countOfCFIs = _EHFrameSection->cfiCount();
+       typename CFISection<A>::CFI_Atom_Info  cfiArray[countOfCFIs];
+       // stack allocate (if not too large) a copy of __eh_frame to apply relocations to
+       uint8_t* ehBuffer = NULL;
+       uint32_t stackAllocSize = 0;
+       if ( (countOfCFIs != 0) && _EHFrameSection->needsRelocating() ) {
+               uint32_t sectSize = _EHFrameSection->machoSection()->size();
+               if ( sectSize > 50*1024 )
+                       ehBuffer = (uint8_t*)malloc(sectSize);
+               else
+                       stackAllocSize = sectSize;
+       }
+       uint32_t ehStackBuffer[1+stackAllocSize/4]; // make 4-byte aligned stack bufffer
+       if ( ehBuffer == NULL )
+               ehBuffer = (uint8_t*)&ehStackBuffer;
+       uint32_t cfiStartsCount = 0;
+       if ( countOfCFIs != 0 ) {
+               _EHFrameSection->cfiParse(*this, ehBuffer, cfiArray, countOfCFIs);
+               // count functions and lsdas
+               for(uint32_t i=0; i < countOfCFIs; ++i) {
+                       if ( cfiArray[i].isCIE )
+                               continue;
+                       //fprintf(stderr, "cfiArray[i].func = 0x%08llX, cfiArray[i].lsda = 0x%08llX, encoding=0x%08X\n", 
+                       //                      (uint64_t)cfiArray[i].u.fdeInfo.function.targetAddress, 
+                       //                      (uint64_t)cfiArray[i].u.fdeInfo.lsda.targetAddress, 
+                       //                      cfiArray[i].u.fdeInfo.compactUnwindInfo);
+                       if ( cfiArray[i].u.fdeInfo.function.targetAddress != CFI_INVALID_ADDRESS )
+                               ++cfiStartsCount;
+                       if ( cfiArray[i].u.fdeInfo.lsda.targetAddress != CFI_INVALID_ADDRESS )
+                               ++cfiStartsCount;
+               }
+       }
+       CFIInfoArray cfis(cfiArray, countOfCFIs);
+       
+       // create sorted array of function starts and lsda starts
+       pint_t cfiStartsArray[cfiStartsCount];
+       uint32_t countOfFDEs = 0;
+       if ( countOfCFIs != 0 ) {
+               int index = 0;
+               for(uint32_t i=0; i < countOfCFIs; ++i) {
+                       if ( cfiArray[i].isCIE )
+                               continue;
+                       if ( cfiArray[i].u.fdeInfo.function.targetAddress != CFI_INVALID_ADDRESS )
+                               cfiStartsArray[index++] = cfiArray[i].u.fdeInfo.function.targetAddress;
+                       if ( cfiArray[i].u.fdeInfo.lsda.targetAddress != CFI_INVALID_ADDRESS )
+                               cfiStartsArray[index++] = cfiArray[i].u.fdeInfo.lsda.targetAddress;
+                       ++countOfFDEs;
+               }
+               ::qsort(cfiStartsArray, cfiStartsCount, sizeof(pint_t), pointerSorter);
+       #ifndef NDEBUG
+               // scan for FDEs claming the same function
+               for(int i=1; i < index; ++i) {
+                       assert( cfiStartsArray[i] != cfiStartsArray[i-1] );
+               }
+       #endif  
+       }
+       
+       Section<A>** sections = _file->_sectionsArray;
+       uint32_t        sectionsCount = _file->_sectionsArrayCount;
+
+       // figure out how many atoms will be allocated and allocate
+       LabelAndCFIBreakIterator breakIterator(sortedSymbolIndexes, _symbolsInSections, cfiStartsArray, 
+                                                                                       cfiStartsCount, _overlappingSymbols);
+       uint32_t computedAtomCount = 0;
+       for (uint32_t i=0; i < sectionsCount; ++i ) {
+               breakIterator.beginSection();
+               uint32_t count = sections[i]->computeAtomCount(*this, breakIterator, cfis);
+               //const macho_section<P>* sect = sections[i]->machoSection();
+               //fprintf(stderr, "computed count=%u for section %s size=%llu\n", count, sect->sectname(), (sect != NULL) ? sect->size() : 0);
+               computedAtomCount += count;
+       }
+       //fprintf(stderr, "allocating %d atoms * sizeof(Atom<A>)=%ld, sizeof(ld::Atom)=%ld\n", computedAtomCount, sizeof(Atom<A>), sizeof(ld::Atom));
+       _file->_atomsArray = new uint8_t[computedAtomCount*sizeof(Atom<A>)];
+       _file->_atomsArrayCount = 0;
+       
+       // have each section append atoms to _atomsArray
+       LabelAndCFIBreakIterator breakIterator2(sortedSymbolIndexes, _symbolsInSections, cfiStartsArray, 
+                                                                                               cfiStartsCount, _overlappingSymbols);
+       for (uint32_t i=0; i < sectionsCount; ++i ) {
+               uint8_t* atoms = _file->_atomsArray + _file->_atomsArrayCount*sizeof(Atom<A>);
+               breakIterator2.beginSection();
+               uint32_t count = sections[i]->appendAtoms(*this, atoms, breakIterator2, cfis);
+               //fprintf(stderr, "append count=%u for section %s\n", count, sections[i]->machoSection()->sectname());
+               _file->_atomsArrayCount += count;
+       }
+       assert( _file->_atomsArrayCount == computedAtomCount && "more atoms allocated than expected");
+
+       
+       // have each section add all fix-ups for its atoms
+       _allFixups.reserve(computedAtomCount*5);
+       for (uint32_t i=0; i < sectionsCount; ++i )
+               sections[i]->makeFixups(*this, cfis);
+       
+       // assign fixups start offset for each atom
+       uint8_t* p = _file->_atomsArray;
+       uint32_t fixupOffset = 0;
+       for(int i=_file->_atomsArrayCount; i > 0; --i) {
+               Atom<A>* atom = (Atom<A>*)p;
+               atom->_fixupsStartIndex = fixupOffset;
+               fixupOffset += atom->_fixupsCount;
+               atom->_fixupsCount = 0;
+               p += sizeof(Atom<A>);
+       }
+       assert(fixupOffset == _allFixups.size());
+       _file->_fixups.reserve(fixupOffset);
+       
+       // copy each fixup for each atom 
+       for(typename std::vector<FixupInAtom>::iterator it=_allFixups.begin(); it != _allFixups.end(); ++it) {
+               uint32_t slot = it->atom->_fixupsStartIndex + it->atom->_fixupsCount;
+               _file->_fixups[slot] = it->fixup;
+               it->atom->_fixupsCount++;
+       }
+       
+       // done with temp vector
+       _allFixups.clear();
+
+       // add unwind info
+       _file->_unwindInfos.reserve(countOfFDEs);
+       for(uint32_t i=0; i < countOfCFIs; ++i) {
+               if ( cfiArray[i].isCIE )
+                       continue;
+               if ( cfiArray[i].u.fdeInfo.function.targetAddress != CFI_INVALID_ADDRESS ) {
+                       ld::Atom::UnwindInfo info;
+                       info.startOffset = 0;
+                       info.unwindInfo = cfiArray[i].u.fdeInfo.compactUnwindInfo;
+                       _file->_unwindInfos.push_back(info);
+                       Atom<A>* func = findAtomByAddress(cfiArray[i].u.fdeInfo.function.targetAddress);
+                       func->setUnwindInfoRange(_file->_unwindInfos.size()-1, 1);
+               }
+       }
+
+       // parse dwarf debug info to get line info
+       this->parseDebugInfo();
+
+       return _file;
+}
+
+
+
+template <> uint8_t Parser<ppc>::loadCommandSizeMask()         { return 0x03; }
+template <> uint8_t Parser<ppc64>::loadCommandSizeMask()       { return 0x07; }
+template <> uint8_t Parser<x86>::loadCommandSizeMask()         { return 0x03; }
+template <> uint8_t Parser<x86_64>::loadCommandSizeMask()      { return 0x07; }
+template <> uint8_t Parser<arm>::loadCommandSizeMask()         { return 0x03; }
+
+template <typename A>
+bool Parser<A>::parseLoadCommands()
+{
+       const macho_header<P>* header = (const macho_header<P>*)_fileContent;
+
+       // set File attributes
+       _file->_canScatterAtoms = (header->flags() & MH_SUBSECTIONS_VIA_SYMBOLS);
+       _file->_cpuSubType = header->cpusubtype();
+       
+       const macho_segment_command<P>* segment = NULL;
+       const uint8_t* const endOfFile = _fileContent + _fileLength;
+       const uint32_t cmd_count = header->ncmds();
+       // <rdar://problem/5394172> an empty .o file with zero load commands will crash linker
+       if ( cmd_count == 0 )
+               return false;
+       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) {
+               uint32_t size = cmd->cmdsize();
+               if ( (size & this->loadCommandSizeMask()) != 0 )
+                       throwf("load command #%d has a unaligned size", i);
+               const uint8_t* endOfCmd = ((uint8_t*)cmd)+cmd->cmdsize();
+               if ( endOfCmd > (uint8_t*)cmdsEnd )
+                       throwf("load command #%d extends beyond the end of the load commands", i);
+               if ( endOfCmd > endOfFile )
+                       throwf("load command #%d extends beyond the end of the file", i);
+               switch (cmd->cmd()) {
+                   case LC_SYMTAB:
+                               {
+                                       const macho_symtab_command<P>* symtab = (macho_symtab_command<P>*)cmd;
+                                       _symbolCount = symtab->nsyms();
+                                       _symbols = (const macho_nlist<P>*)(_fileContent + symtab->symoff());
+                                       _strings = (char*)_fileContent + symtab->stroff();
+                                       _stringsSize = symtab->strsize();
+                                       if ( (symtab->symoff() + _symbolCount*sizeof(macho_nlist<P>)) > _fileLength )
+                                               throw "mach-o symbol table extends beyond end of file";
+                                       if ( (_strings + _stringsSize) > (char*)endOfFile )
+                                               throw "mach-o string pool extends beyond end of file";
+                                       if ( _indirectTable == NULL ) {
+                                               if ( _undefinedEndIndex == 0 ) {
+                                                       _undefinedStartIndex = 0;
+                                                       _undefinedEndIndex = symtab->nsyms();
+                                               }
+                                       }
+                               }
+                               break;
+                       case LC_DYSYMTAB:
+                               {
+                                       const macho_dysymtab_command<P>* dsymtab = (macho_dysymtab_command<P>*)cmd;
+                                       _indirectTable = (uint32_t*)(_fileContent + dsymtab->indirectsymoff());
+                                       _indirectTableCount = dsymtab->nindirectsyms();
+                                       if ( &_indirectTable[_indirectTableCount] > (uint32_t*)endOfFile )
+                                               throw "indirect symbol table extends beyond end of file";
+                                       _undefinedStartIndex = dsymtab->iundefsym();
+                                       _undefinedEndIndex = _undefinedStartIndex + dsymtab->nundefsym();
+                               }
+                               break;
+                   case LC_UUID:
+                               _hasUUID = true;
+                               break;
+
+                       default:
+                               if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
+                                       if ( segment != NULL )
+                                               throw "more than one LC_SEGMENT found in object file";
+                                       segment = (macho_segment_command<P>*)cmd;
+                               }
+                               break;
+               }
+               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);
+       }
+
+       // record range of sections
+       if ( segment == NULL ) 
+               throw "missing LC_SEGMENT";
+       _sectionsStart = (macho_section<P>*)((char*)segment + sizeof(macho_segment_command<P>));
+       _machOSectionsCount = segment->nsects();
+       
+       return true;
+}
+
+template <>
+void Parser<arm>::checkForLSDA()
+{
+       // ARM has no FDEs, so need labels to break up section into atoms
+}
+
+template <typename A>
+void Parser<A>::checkForLSDA()
+{
+       // ignore labels on __gcc_except_tab section, we'll break it into atoms based on FDE info
+       for (uint32_t i=0; i < _machOSectionsCount; ++i) {
+               const macho_section<P>* sect = &_sectionsStart[i];
+               if ( strncmp(sect->sectname(), "__gcc_except_tab", 16) == 0 ) {
+                       if ( strcmp(sect->segname(), "__TEXT") == 0 ) {
+                               assert(_lsdaTextSectionNum == 0);
+                               _lsdaTextSectionNum = i+1;
+                       }
+                       else if ( strcmp(sect->segname(), "__DATA") == 0 ) {
+                               assert(_lsdaDataSectionNum == 0);
+                               _lsdaDataSectionNum = i+1;
+                       }
+               }
+       }
+}
+
+
+template <typename A>
+void Parser<A>::prescanSymbolTable()
+{
+       _tentativeDefinitionCount = 0;
+       _absoluteSymbolCount = 0;
+       _symbolsInSections = 0;
+       for (uint32_t i=0; i < this->_symbolCount; ++i) {
+               const macho_nlist<P>& sym =     symbolFromIndex(i);
+               // ignore stabs
+               if ( (sym.n_type() & N_STAB) != 0 )
+                       continue;
+                       
+               // look at undefines
+               const char* symbolName = this->nameFromSymbol(sym);
+               if ( (sym.n_type() & N_TYPE) == N_UNDF ) {
+                       if ( sym.n_value() != 0 ) {
+                               // count tentative definitions
+                               ++_tentativeDefinitionCount;
+                       }
+                       else if ( strncmp(symbolName, "___dtrace_", 10) == 0 ) {
+                               // any undefined starting with __dtrace_*$ that is not ___dtrace_probe$* or ___dtrace_isenabled$*
+                               // is extra provider info
+                               if ( (strncmp(&symbolName[10], "probe$", 6) != 0) && (strncmp(&symbolName[10], "isenabled$", 10) != 0) ) {
+                                       _dtraceProviderInfo.push_back(symbolName);
+                               }
+                       }
+                       continue;
+               }
+                                               
+               // count absolute symbols
+               if ( (sym.n_type() & N_TYPE) == N_ABS ) {
+                       const char* absName = this->nameFromSymbol(sym);
+                       // ignore .objc_class_name_* symbols 
+                       if ( strncmp(absName, ".objc_class_name_", 17) == 0 ) {
+                               _AppleObjc = true;
+                               continue;
+                       }
+                       // ignore .objc_class_name_* symbols 
+                       if ( strncmp(absName, ".objc_category_name_", 20) == 0 )
+                               continue;
+                       // ignore empty *.eh symbols
+                       if ( strcmp(&absName[strlen(absName)-3], ".eh") == 0 )
+                               continue;
+                       ++_absoluteSymbolCount;
+               }
+               
+               // only look at definitions
+               if ( (sym.n_type() & N_TYPE) != N_SECT )
+                       continue;
+               
+               // 'L' labels do not denote atom breaks
+               if ( symbolName[0] == 'L' )
+                       continue;
+               
+               // ignore labels in __gcc_except_tab section
+               if ( (_lsdaTextSectionNum != 0) && (sym.n_sect() == _lsdaTextSectionNum) )
+                       continue;
+               if ( (_lsdaDataSectionNum != 0) && (sym.n_sect() == _lsdaDataSectionNum) )
+                       continue;
+               
+               // how many def syms in each section
+               if ( sym.n_sect() > _machOSectionsCount )
+                       throw "bad n_sect in symbol table";
+                       
+               _symbolsInSections++;
+       }
+}
+
+template <typename A>
+int Parser<A>::symbolIndexSorter(void* extra, const void* l, const void* r)
+{
+       Parser<A>* parser = (Parser<A>*)extra;
+       const uint32_t* left = (uint32_t*)l;
+       const uint32_t* right = (uint32_t*)r;
+       const macho_nlist<P>& leftSym = parser->symbolFromIndex(*left);
+       const macho_nlist<P>& rightSym = parser->symbolFromIndex(*right);
+       // can't just return difference because 64-bit diff does not fit in 32-bit return type
+       int64_t result = leftSym.n_value() - rightSym.n_value();
+       if ( result == 0 ) {
+               // two symbols with same address
+               // if in different sections, sort earlier section first
+               if ( leftSym.n_sect() != rightSym.n_sect() )
+                       return (leftSym.n_sect() - rightSym.n_sect());
+               //, means one is an alias
+               // if only one is global, make the other an alias (sort first)
+               if ( (leftSym.n_type() & N_EXT) != (rightSym.n_type() & N_EXT) ) {
+                       if ( (rightSym.n_type() & N_EXT) != 0 )
+                               return -1;
+                       else
+                               return 1;
+               }
+               // if both are global, make alphabetically last one be the alias
+               return ( strcmp(parser->nameFromSymbol(rightSym), parser->nameFromSymbol(leftSym)) );
+       }
+       else if ( result < 0 )
+               return -1;
+       else
+               return 1;
+}
+
+template <typename A>
+void Parser<A>::makeSortedSymbolsArray(uint32_t array[])
+{
+       uint32_t* p = array;
+       for (uint32_t i=0; i < this->_symbolCount; ++i) {
+               const macho_nlist<P>& sym =     symbolFromIndex(i);
+               // ignore stabs
+               if ( (sym.n_type() & N_STAB) != 0 )
+                       continue;
+               
+               // only look at definitions
+               if ( (sym.n_type() & N_TYPE) != N_SECT )
+                       continue;
+               
+               // 'L' labels do not denote atom breaks
+               const char* symbolName = this->nameFromSymbol(sym);
+               if ( symbolName[0] == 'L' )
+                       continue;
+
+               // ignore labels in __gcc_except_tab section
+               if ( (_lsdaTextSectionNum != 0) && (sym.n_sect() == _lsdaTextSectionNum) )
+                       continue;
+               if ( (_lsdaDataSectionNum != 0) && (sym.n_sect() == _lsdaDataSectionNum) )
+                       continue;
+               
+               // how many def syms in each section
+               if ( sym.n_sect() > _machOSectionsCount )
+                       throw "bad n_sect in symbol table";
+                       
+               // append to array
+               *p++ = i;
+       }
+       assert(p == &array[_symbolsInSections] && "second pass over symbol table yield a different number of symbols");
+       
+       // sort by symbol table address
+       ::qsort_r(array, _symbolsInSections, sizeof(uint32_t), this, &symbolIndexSorter);
+       
+       // look for two symbols at same address
+       _overlappingSymbols = false;
+       for (unsigned int i=1; i < _symbolsInSections; ++i) {
+               if ( symbolFromIndex(array[i-1]).n_value() == symbolFromIndex(array[i]).n_value() ) {
+                       //fprintf(stderr, "overlapping symbols at 0x%08llX\n", symbolFromIndex(array[i-1]).n_value());
+                       _overlappingSymbols = true;
+               }
+       }
+
+       //fprintf(stderr, "sorted symbols:\n");
+       //for(unsigned int i=0; i < _symbolsInSections; ++i ) 
+       //      fprintf(stderr, "0x%09llX symIndex=%3d sectNum=%2d, %s\n", symbolFromIndex(array[i]).n_value(), array[i], symbolFromIndex(array[i]).n_sect(), nameFromSymbol(symbolFromIndex(array[i])) );
+}
+
+
+template <typename A>
+void Parser<A>::makeSections()
+{
+       // classify each section by type
+       // compute how many Section objects will be needed and total size for all
+       unsigned int totalSectionsSize = 0;
+       uint8_t machOSectsStorage[sizeof(MachOSectionAndSectionClass<P>)*(_machOSectionsCount+2)]; // also room for tentative-defs and absolute symbols
+       // allocate raw storage for all section objects on stack
+       MachOSectionAndSectionClass<P>* machOSects = (MachOSectionAndSectionClass<P>*)machOSectsStorage;
+       unsigned int count = 0;
+       for (uint32_t i=0; i < _machOSectionsCount; ++i) {
+               const macho_section<P>* sect = &_sectionsStart[i];
+               // ignore dwarf sections
+               if ( (sect->flags() & S_ATTR_DEBUG) != 0 ) {
+                       // note that .o file has dwarf
+                       _file->_debugInfoKind = ld::relocatable::File::kDebugInfoDwarf;
+                       // save off iteresting dwarf sections
+                       if ( strcmp(sect->sectname(), "__debug_info") == 0 )
+                               _file->_dwarfDebugInfoSect = sect;
+                       else if ( strcmp(sect->sectname(), "__debug_abbrev") == 0 )
+                               _file->_dwarfDebugAbbrevSect = sect;
+                       else if ( strcmp(sect->sectname(), "__debug_line") == 0 )
+                               _file->_dwarfDebugLineSect = sect;
+                       else if ( strcmp(sect->sectname(), "__debug_str") == 0 )
+                               _file->_dwarfDebugStringSect = sect;
+                       // linker does not propagate dwarf sections to output file
+                       continue;
+               }
+               // ignore empty __OBJC sections
+               if ( (sect->size() == 0) && (strcmp(sect->segname(), "__OBJC") == 0) )
+                       continue;
+               // objc image info section is really attributes and not content
+               if ( ((strcmp(sect->sectname(), "__image_info") == 0) && (strcmp(sect->segname(), "__OBJC") == 0))
+                       || ((strncmp(sect->sectname(), "__objc_imageinfo", 16) == 0) && (strcmp(sect->segname(), "__DATA") == 0)) ) {
+                       //      struct objc_image_info  {
+                       //              uint32_t        version;        // initially 0
+                       //              uint32_t        flags;
+                       //      };
+                       // #define OBJC_IMAGE_SUPPORTS_GC   2
+                       // #define OBJC_IMAGE_GC_ONLY       4
+                       //
+                       const uint32_t* contents = (uint32_t*)(_file->fileContent()+sect->offset());
+                       if ( (sect->size() >= 8) && (contents[0] == 0) ) {
+                               uint32_t flags = E::get32(contents[1]);
+                               if ( (flags & 4) == 4 )
+                                       _file->_objConstraint = ld::File::objcConstraintGC;
+                               else if ( (flags & 2) == 2 )
+                                       _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(), sect->sectname(), sect->size(), _file->path());
+                               }
+                       }
+                       else {
+                               warning("can't parse %s/%s section in %s", sect->segname(), sect->sectname(), _file->path());
+                       }
+                       continue;
+               }
+               machOSects[count].sect = sect;
+               switch ( sect->flags() & SECTION_TYPE ) {
+                       case S_SYMBOL_STUBS:
+                               if ( _stubsSectionNum == 0 ) {
+                                       _stubsSectionNum = i+1;
+                                       _stubsMachOSection = sect;
+                               }
+                               else
+                                       assert(1 && "multiple S_SYMBOL_STUBS sections");
+                       case S_LAZY_SYMBOL_POINTERS:
+                               break;
+                       case S_4BYTE_LITERALS:
+                               totalSectionsSize += sizeof(Literal4Section<A>);
+                               machOSects[count++].type = sectionTypeLiteral4;
+                               break;
+                       case S_8BYTE_LITERALS:
+                               totalSectionsSize += sizeof(Literal8Section<A>);
+                               machOSects[count++].type = sectionTypeLiteral8;
+                               break;
+                       case S_16BYTE_LITERALS:
+                               totalSectionsSize += sizeof(Literal16Section<A>);
+                               machOSects[count++].type = sectionTypeLiteral16;
+                               break;
+                       case S_NON_LAZY_SYMBOL_POINTERS:
+                               totalSectionsSize += sizeof(NonLazyPointerSection<A>);
+                               machOSects[count++].type = sectionTypeNonLazy;
+                               break;
+                       case S_LITERAL_POINTERS:
+                               if ( (strcmp(sect->segname(), "__OBJC") == 0) && (strcmp(sect->sectname(), "__cls_refs") == 0) ) {
+                                       totalSectionsSize += sizeof(Objc1ClassReferences<A>);
+                                       machOSects[count++].type = sectionTypeObjC1ClassRefs;
+                               }
+                               else {
+                                       totalSectionsSize += sizeof(PointerToCStringSection<A>);
+                                       machOSects[count++].type = sectionTypeCStringPointer;
+                               }
+                               break;
+                       case S_CSTRING_LITERALS:
+                               totalSectionsSize += sizeof(CStringSection<A>);
+                               machOSects[count++].type = sectionTypeCString;
+                               break;
+                       case S_MOD_INIT_FUNC_POINTERS:
+                       case S_MOD_TERM_FUNC_POINTERS:
+                       case S_THREAD_LOCAL_INIT_FUNCTION_POINTERS:
+                       case S_INTERPOSING:
+                       case S_ZEROFILL:
+                       case S_REGULAR:
+                       case S_COALESCED:
+                       case S_THREAD_LOCAL_REGULAR:
+                       case S_THREAD_LOCAL_ZEROFILL:
+                               if ( (strcmp(sect->segname(), "__TEXT") == 0) && (strcmp(sect->sectname(), "__eh_frame") == 0) ) {
+                                       totalSectionsSize += sizeof(CFISection<A>);
+                                       machOSects[count++].type = sectionTypeCFI;
+                               }
+                               else if ( (strcmp(sect->segname(), "__DATA") == 0) && (strcmp(sect->sectname(), "__cfstring") == 0) ) {
+                                       totalSectionsSize += sizeof(CFStringSection<A>);
+                                       machOSects[count++].type = sectionTypeCFString;
+                               }
+                               else if ( (strcmp(sect->segname(), "__TEXT") == 0) && (strcmp(sect->sectname(), "__ustring") == 0) ) {
+                                       totalSectionsSize += sizeof(UTF16StringSection<A>);
+                                       machOSects[count++].type = sectionTypeUTF16Strings;
+                               }
+                               else if ( (strcmp(sect->segname(), "__DATA") == 0) && (strncmp(sect->sectname(), "__objc_classrefs", 16) == 0) ) {
+                                       totalSectionsSize += sizeof(ObjC2ClassRefsSection<A>);
+                                       machOSects[count++].type = sectionTypeObjC2ClassRefs;
+                               }
+                               else if ( (strcmp(sect->segname(), "__DATA") == 0) && (strcmp(sect->sectname(), "__objc_catlist") == 0) ) {
+                                       totalSectionsSize += sizeof(ObjC2CategoryListSection<A>);
+                                       machOSects[count++].type = typeObjC2CategoryList;
+                               }
+                               else if ( _AppleObjc && (strcmp(sect->segname(), "__OBJC") == 0) && (strcmp(sect->sectname(), "__class") == 0) ) {
+                                       totalSectionsSize += sizeof(ObjC1ClassSection<A>);
+                                       machOSects[count++].type = sectionTypeObjC1Classes;
+                               }
+                               else {
+                                       totalSectionsSize += sizeof(SymboledSection<A>);
+                                       machOSects[count++].type = sectionTypeSymboled;
+                               }
+                               break;
+                       case S_THREAD_LOCAL_VARIABLES:
+                               totalSectionsSize += sizeof(TLVDefsSection<A>);
+                               machOSects[count++].type = sectionTypeTLVDefs;
+                               break;
+                       case S_THREAD_LOCAL_VARIABLE_POINTERS:
+                       default:
+                               throwf("unknown section type %d", sect->flags() & SECTION_TYPE);
+               }
+       }
+       
+       // sort by address (mach-o object files don't aways have sections sorted)
+       ::qsort(machOSects, count, sizeof(MachOSectionAndSectionClass<P>), MachOSectionAndSectionClass<P>::sorter);
+               
+       // we will synthesize a dummy Section<A> object for tentative definitions
+       if ( _tentativeDefinitionCount > 0 ) {
+               totalSectionsSize += sizeof(TentativeDefinitionSection<A>);
+               machOSects[count++].type = sectionTypeTentativeDefinitions;
+       }
+       
+       // we will synthesize a dummy Section<A> object for Absolute symbols
+       if ( _absoluteSymbolCount > 0 ) {
+               totalSectionsSize += sizeof(AbsoluteSymbolSection<A>);
+               machOSects[count++].type = sectionTypeAbsoluteSymbols;
+       }
+
+       // allocate one block for all Section objects as well as pointers to each
+       uint8_t* space = new uint8_t[totalSectionsSize+count*sizeof(Section<A>*)];
+       _file->_sectionsArray = (Section<A>**)space;
+       _file->_sectionsArrayCount = count;
+       Section<A>** objects = _file->_sectionsArray;
+       space += count*sizeof(Section<A>*);
+       for (uint32_t i=0; i < count; ++i) {
+               switch ( machOSects[i].type ) {
+                       case sectionTypeIgnore:
+                               break;
+                       case sectionTypeLiteral4:
+                               *objects++ = new (space) Literal4Section<A>(*this, *_file, machOSects[i].sect);
+                               space += sizeof(Literal4Section<A>);
+                               break;
+                       case sectionTypeLiteral8:
+                               *objects++ = new (space) Literal8Section<A>(*this, *_file, machOSects[i].sect);
+                               space += sizeof(Literal8Section<A>);
+                               break;
+                       case sectionTypeLiteral16:
+                               *objects++ = new (space) Literal16Section<A>(*this, *_file, machOSects[i].sect);
+                               space += sizeof(Literal16Section<A>);
+                               break;
+                       case sectionTypeNonLazy:
+                               *objects++ = new (space) NonLazyPointerSection<A>(*this, *_file, machOSects[i].sect);
+                               space += sizeof(NonLazyPointerSection<A>);
+                               break;
+                       case sectionTypeCFI:
+                               _EHFrameSection = new (space) CFISection<A>(*this, *_file, machOSects[i].sect);
+                               *objects++ = _EHFrameSection;
+                               space += sizeof(CFISection<A>);
+                               break;
+                       case sectionTypeCString:
+                               *objects++ = new (space) CStringSection<A>(*this, *_file, machOSects[i].sect);
+                               space += sizeof(CStringSection<A>);
+                               break;
+                       case sectionTypeCStringPointer:
+                               *objects++ = new (space) PointerToCStringSection<A>(*this, *_file, machOSects[i].sect);
+                               space += sizeof(PointerToCStringSection<A>);
+                               break;
+                       case sectionTypeObjC1ClassRefs:
+                               *objects++ = new (space) Objc1ClassReferences<A>(*this, *_file, machOSects[i].sect);
+                               space += sizeof(Objc1ClassReferences<A>);
+                               break;
+                       case sectionTypeUTF16Strings:
+                               *objects++ = new (space) UTF16StringSection<A>(*this, *_file, machOSects[i].sect);
+                               space += sizeof(UTF16StringSection<A>);
+                               break;
+                       case sectionTypeCFString:
+                               *objects++ = new (space) CFStringSection<A>(*this, *_file, machOSects[i].sect);
+                               space += sizeof(CFStringSection<A>);
+                               break;
+                       case sectionTypeObjC2ClassRefs:
+                               *objects++ = new (space) ObjC2ClassRefsSection<A>(*this, *_file, machOSects[i].sect);
+                               space += sizeof(ObjC2ClassRefsSection<A>);
+                               break;
+                       case typeObjC2CategoryList:
+                               *objects++ = new (space) ObjC2CategoryListSection<A>(*this, *_file, machOSects[i].sect);
+                               space += sizeof(ObjC2CategoryListSection<A>);
+                               break;
+                       case sectionTypeObjC1Classes: 
+                               *objects++ = new (space) ObjC1ClassSection<A>(*this, *_file, machOSects[i].sect);
+                               space += sizeof(ObjC1ClassSection<A>);
+                               break;
+                       case sectionTypeSymboled:
+                               *objects++ = new (space) SymboledSection<A>(*this, *_file, machOSects[i].sect);
+                               space += sizeof(SymboledSection<A>);
+                               break;
+                       case sectionTypeTLVDefs:
+                               *objects++ = new (space) TLVDefsSection<A>(*this, *_file, machOSects[i].sect);
+                               space += sizeof(TLVDefsSection<A>);
+                               break;
+                       case sectionTypeTentativeDefinitions:
+                               *objects++ = new (space) TentativeDefinitionSection<A>(*this, *_file);
+                               space += sizeof(TentativeDefinitionSection<A>);
+                               break;
+                       case sectionTypeAbsoluteSymbols:
+                               _absoluteSection = new (space) AbsoluteSymbolSection<A>(*this, *_file);
+                               *objects++ = _absoluteSection;
+                               space += sizeof(AbsoluteSymbolSection<A>);
+                               break;
+                       default:
+                               throw "internal error uknown SectionType";
+               }
+       }
+}
+
+
+template <typename A>
+Section<A>* Parser<A>::sectionForAddress(typename A::P::uint_t addr)
+{
+       for (uint32_t i=0; i < _file->_sectionsArrayCount; ++i ) {
+               const macho_section<typename A::P>* sect = _file->_sectionsArray[i]->machoSection();
+               // TentativeDefinitionSection and AbsoluteSymbolSection have no mach-o section
+               if ( sect != NULL ) {
+                       if ( (sect->addr() <= addr) && (addr < (sect->addr()+sect->size())) ) {
+                               return _file->_sectionsArray[i];
+                       }
+               }
+       }
+       // not strictly in any section
+       // may be in a zero length section
+       for (uint32_t i=0; i < _file->_sectionsArrayCount; ++i ) {
+               const macho_section<typename A::P>* sect = _file->_sectionsArray[i]->machoSection();
+               // TentativeDefinitionSection and AbsoluteSymbolSection have no mach-o section
+               if ( sect != NULL ) {
+                       if ( (sect->addr() == addr) && (sect->size() == 0) ) {
+                               return _file->_sectionsArray[i];
+                       }
+               }
+       }
+       
+       throwf("sectionForAddress(0x%llX) address not in any section", (uint64_t)addr);
+}
+
+template <typename A>
+Section<A>* Parser<A>::sectionForNum(unsigned int num)
+{
+       for (uint32_t i=0; i < _file->_sectionsArrayCount; ++i ) {
+               const macho_section<typename A::P>* sect = _file->_sectionsArray[i]->machoSection();
+               // TentativeDefinitionSection and AbsoluteSymbolSection have no mach-o section
+               if ( sect != NULL ) {
+                       if ( num == (unsigned int)((sect - _sectionsStart)+1) )
+                               return _file->_sectionsArray[i];
+               }
+       }
+       throwf("sectionForNum(%u) section number not for any section", num);
+}
+
+template <typename A>
+Atom<A>* Parser<A>::findAtomByAddress(pint_t addr)
+{
+       Section<A>* section = this->sectionForAddress(addr);
+       return section->findAtomByAddress(addr);
+}
+
+template <typename A>
+Atom<A>* Parser<A>::findAtomByAddressOrNullIfStub(pint_t addr)
+{
+       if ( hasStubsSection() && (_stubsMachOSection->addr() <= addr) && (addr < (_stubsMachOSection->addr()+_stubsMachOSection->size())) ) 
+               return NULL;
+       return findAtomByAddress(addr);
+}
+
+template <typename A>
+Atom<A>* Parser<A>::findAtomByAddressOrLocalTargetOfStub(pint_t addr, uint32_t* offsetInAtom)
+{
+       if ( hasStubsSection() && (_stubsMachOSection->addr() <= addr) && (addr < (_stubsMachOSection->addr()+_stubsMachOSection->size())) ) {
+               // target is a stub, remove indirection
+               uint32_t symbolIndex = this->symbolIndexFromIndirectSectionAddress(addr, _stubsMachOSection);
+               assert(symbolIndex != INDIRECT_SYMBOL_LOCAL);
+               const macho_nlist<P>& sym = this->symbolFromIndex(symbolIndex);
+               // can't be to external weak symbol
+               assert( (this->combineFromSymbol(sym) != ld::Atom::combineByName) || (this->scopeFromSymbol(sym) != ld::Atom::scopeGlobal) );
+               *offsetInAtom = 0;
+               return this->findAtomByName(this->nameFromSymbol(sym));
+       }
+       Atom<A>* target = this->findAtomByAddress(addr);
+       *offsetInAtom = addr - target->_objAddress;
+       return target;
+}
+
+template <typename A>
+Atom<A>* Parser<A>::findAtomByName(const char* name)
+{
+       uint8_t* p = _file->_atomsArray;
+       for(int i=_file->_atomsArrayCount; i > 0; --i) {
+               Atom<A>* atom = (Atom<A>*)p;
+               if ( strcmp(name, atom->name()) == 0 )
+                       return atom;
+               p += sizeof(Atom<A>);
+       }
+       return NULL;
+}
+
+template <typename A>
+void Parser<A>::findTargetFromAddress(pint_t addr, TargetDesc& target)
+{
+       if ( hasStubsSection() && (_stubsMachOSection->addr() <= addr) && (addr < (_stubsMachOSection->addr()+_stubsMachOSection->size())) ) {
+               // target is a stub, remove indirection
+               uint32_t symbolIndex = this->symbolIndexFromIndirectSectionAddress(addr, _stubsMachOSection);
+               assert(symbolIndex != INDIRECT_SYMBOL_LOCAL);
+               const macho_nlist<P>& sym = this->symbolFromIndex(symbolIndex);
+               target.atom = NULL;
+               target.name = this->nameFromSymbol(sym);
+               target.weakImport = this->weakImportFromSymbol(sym);
+               target.addend = 0;
+               return;
+       }
+       Section<A>* section = this->sectionForAddress(addr);
+       target.atom = section->findAtomByAddress(addr);
+       target.addend = addr - target.atom->_objAddress;
+       target.weakImport = false;
+       target.name = NULL;
+}
+
+template <typename A>
+void Parser<A>::findTargetFromAddress(pint_t baseAddr, pint_t addr, TargetDesc& target)
+{
+       findTargetFromAddress(baseAddr, target);
+       target.addend = addr - target.atom->_objAddress;
+}
+
+template <typename A>
+void Parser<A>::findTargetFromAddressAndSectionNum(pint_t addr, unsigned int sectNum, TargetDesc& target)
+{
+       if ( sectNum == R_ABS ) {
+               // target is absolute symbol that corresponds to addr
+               if ( _absoluteSection != NULL ) {
+                       target.atom = _absoluteSection->findAbsAtomForValue(addr);
+                       if ( target.atom != NULL ) {
+                               target.name = NULL;
+                               target.weakImport = false;
+                               target.addend = 0;
+                               return;
+                       }
+               }
+               throwf("R_ABS reloc but no absolute symbol at target address");
+       }
+
+       if ( hasStubsSection() && (stubsSectionNum() == sectNum) ) {
+               // target is a stub, remove indirection
+               uint32_t symbolIndex = this->symbolIndexFromIndirectSectionAddress(addr, _stubsMachOSection);
+               assert(symbolIndex != INDIRECT_SYMBOL_LOCAL);
+               const macho_nlist<P>& sym = this->symbolFromIndex(symbolIndex);
+               // use direct reference when stub is to a static function
+               if ( ((sym.n_type() & N_TYPE) == N_SECT) && (((sym.n_type() & N_EXT) == 0) || (this->nameFromSymbol(sym)[0] == 'L')) ) {
+                       this->findTargetFromAddressAndSectionNum(sym.n_value(), sym.n_sect(), target);
+               }
+               else {
+                       target.atom = NULL;
+                       target.name = this->nameFromSymbol(sym);
+                       target.weakImport = this->weakImportFromSymbol(sym);
+                       target.addend = 0;
+               }
+               return;
+       }
+       Section<A>* section = this->sectionForNum(sectNum);
+       target.atom = section->findAtomByAddress(addr);
+       if ( target.atom == NULL ) {
+               typedef typename A::P::sint_t sint_t;
+               sint_t a = (sint_t)addr;
+               sint_t sectStart = (sint_t)(section->machoSection()->addr());
+               sint_t sectEnd  = sectStart + section->machoSection()->size();
+               if ( a < sectStart ) {
+                       // target address is before start of section, so must be negative addend
+                       target.atom = section->findAtomByAddress(sectStart);
+                       target.addend = a - sectStart;
+                       target.weakImport = false;
+                       target.name = NULL;
+                       return;
+               }
+               else if ( a >= sectEnd ) {
+                       target.atom = section->findAtomByAddress(sectEnd-1);
+                       target.addend = a - sectEnd;
+                       target.weakImport = false;
+                       target.name = NULL;
+                       return;
+               }
+       }
+       assert(target.atom != NULL);
+       target.addend = addr - target.atom->_objAddress;
+       target.weakImport = false;
+       target.name = NULL;
+}
+
+template <typename A>
+void Parser<A>::addDtraceExtraInfos(const SourceLocation& src, const char* providerName)
+{
+       // for every ___dtrace_stability$* and ___dtrace_typedefs$* undefine with
+       // a matching provider name, add a by-name kDtraceTypeReference at probe site
+       const char* dollar = strchr(providerName, '$');
+       if ( dollar != NULL ) {
+               int providerNameLen = dollar-providerName+1;
+               for ( std::vector<const char*>::iterator it = _dtraceProviderInfo.begin(); it != _dtraceProviderInfo.end(); ++it) {
+                       const char* typeDollar = strchr(*it, '$');
+                       if ( typeDollar != NULL ) {
+                               if ( strncmp(typeDollar+1, providerName, providerNameLen) == 0 ) {
+                                       addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindDtraceExtra,false, *it);
+                               }
+                       }
+               }
+       }
+}
+
+template <typename A>
+const char* Parser<A>::scanSymbolTableForAddress(uint64_t addr)
+{
+       uint64_t closestSymAddr = 0;
+       const char* closestSymName = NULL;
+       for (uint32_t i=0; i < this->_symbolCount; ++i) {
+               const macho_nlist<P>& sym =     symbolFromIndex(i);
+               // ignore stabs
+               if ( (sym.n_type() & N_STAB) != 0 )
+                       continue;
+               
+               // only look at definitions
+               if ( (sym.n_type() & N_TYPE) != N_SECT )
+                       continue;
+
+               // return with exact match
+               if ( sym.n_value() == addr )
+                       return nameFromSymbol(sym);
+               
+               // record closest seen so far
+               if ( (sym.n_value() < addr) && ((sym.n_value() > closestSymAddr) || (closestSymName == NULL)) )
+                       closestSymName = nameFromSymbol(sym);
+       }
+
+       return (closestSymName != NULL) ? closestSymName : "unknown";
+}
+
+
+template <typename A>
+void Parser<A>::addFixups(const SourceLocation& src, ld::Fixup::Kind setKind, const TargetDesc& target)
+{
+       // some fixup pairs can be combined
+       ld::Fixup::Cluster cl = ld::Fixup::k1of3;
+       ld::Fixup::Kind firstKind = ld::Fixup::kindSetTargetAddress;
+       bool combined = false;
+       if ( target.addend == 0 ) {
+               cl = ld::Fixup::k1of1;
+               combined = true;
+               switch ( setKind ) {
+                       case ld::Fixup::kindStoreLittleEndian32:
+                               firstKind = ld::Fixup::kindStoreTargetAddressLittleEndian32;
+                               break;
+                       case ld::Fixup::kindStoreLittleEndian64:
+                               firstKind = ld::Fixup::kindStoreTargetAddressLittleEndian64;
+                               break;
+                       case ld::Fixup::kindStoreBigEndian32:
+                               firstKind = ld::Fixup::kindStoreTargetAddressBigEndian32;
+                               break;
+                       case ld::Fixup::kindStoreBigEndian64:
+                               firstKind = ld::Fixup::kindStoreTargetAddressBigEndian64;
+                               break;
+                       case ld::Fixup::kindStoreX86BranchPCRel32:
+                               firstKind = ld::Fixup::kindStoreTargetAddressX86BranchPCRel32;
+                               break;
+                       case ld::Fixup::kindStoreX86PCRel32:
+                               firstKind = ld::Fixup::kindStoreTargetAddressX86PCRel32;
+                               break;
+                       case ld::Fixup::kindStoreX86PCRel32GOTLoad:
+                               firstKind = ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad;
+                               break;
+                       case ld::Fixup::kindStoreX86PCRel32TLVLoad:
+                               firstKind = ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad;
+                               break;
+                       case ld::Fixup::kindStoreX86Abs32TLVLoad:
+                               firstKind = ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad;
+                               break;
+                       case ld::Fixup::kindStoreARMBranch24:
+                               firstKind = ld::Fixup::kindStoreTargetAddressARMBranch24;
+                               break;
+                       case ld::Fixup::kindStoreThumbBranch22:
+                               firstKind = ld::Fixup::kindStoreTargetAddressThumbBranch22;
+                               break;
+                       case ld::Fixup::kindStorePPCBranch24:
+                               firstKind = ld::Fixup::kindStoreTargetAddressPPCBranch24;
+                               break;
+                       default:
+                               combined = false;
+                               cl = ld::Fixup::k1of2;
+                               break;
+               }
+       }
+
+       if ( target.atom != NULL ) {
+               if ( target.atom->scope() == ld::Atom::scopeTranslationUnit ) {
+                       addFixup(src, cl, firstKind, target.atom);
+               }
+               else if ( (target.atom->combine() == ld::Atom::combineByNameAndContent) || (target.atom->combine() == ld::Atom::combineByNameAndReferences) ) {
+                       addFixup(src, cl, firstKind, ld::Fixup::bindingByContentBound, target.atom);
+               }
+               else if ( (src.atom->section().type() == ld::Section::typeCFString) && (src.offsetInAtom != 0) ) {
+                       // backing string in CFStrings should always be direct
+                       addFixup(src, cl, firstKind, target.atom);
+               }
+               else {
+                       // change direct fixup to by-name fixup
+                       addFixup(src, cl, firstKind, false, target.atom->name());
+               }
+       }
+       else {
+               addFixup(src, cl, firstKind, target.weakImport, target.name);
+       }
+       if ( target.addend == 0 ) {
+               if ( ! combined )
+                       addFixup(src, ld::Fixup::k2of2, setKind);
+       }
+       else {
+               addFixup(src, ld::Fixup::k2of3, ld::Fixup::kindAddAddend, target.addend);
+               addFixup(src, ld::Fixup::k3of3, setKind);
+       }
+}
+
+template <typename A>
+void Parser<A>::addFixups(const SourceLocation& src, ld::Fixup::Kind kind, const TargetDesc& target, const TargetDesc& picBase)
+{
+       ld::Fixup::Cluster cl = (target.addend == 0) ? ld::Fixup::k1of4 : ld::Fixup::k1of5;
+       if ( target.atom != NULL ) {
+               if ( target.atom->scope() == ld::Atom::scopeTranslationUnit ) {
+                       addFixup(src, cl, ld::Fixup::kindSetTargetAddress, target.atom);
+               }
+               else if ( (target.atom->combine() == ld::Atom::combineByNameAndContent) || (target.atom->combine() == ld::Atom::combineByNameAndReferences) ) {
+                       addFixup(src, cl, ld::Fixup::kindSetTargetAddress, ld::Fixup::bindingByContentBound, target.atom);
+               }
+               else {
+                       addFixup(src, cl, ld::Fixup::kindSetTargetAddress, false, target.atom->name());
+               }
+       }
+       else {
+               addFixup(src, cl, ld::Fixup::kindSetTargetAddress, target.weakImport, target.name);
+       }
+       if ( target.addend == 0 ) {
+               assert(picBase.atom != NULL);
+               addFixup(src, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, picBase.atom);
+               addFixup(src, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, picBase.addend);
+               addFixup(src, ld::Fixup::k4of4, kind);
+       }
+       else {
+               addFixup(src, ld::Fixup::k2of5, ld::Fixup::kindAddAddend, target.addend);
+               addFixup(src, ld::Fixup::k3of5, ld::Fixup::kindSubtractTargetAddress, picBase.atom);
+               addFixup(src, ld::Fixup::k4of5, ld::Fixup::kindSubtractAddend, picBase.addend);
+               addFixup(src, ld::Fixup::k5of5, kind);
+       }
+}
+
+
+
+template <typename A>
+uint32_t TentativeDefinitionSection<A>::computeAtomCount(class Parser<A>& parser, 
+                                                                                                                       struct Parser<A>::LabelAndCFIBreakIterator& it, 
+                                                                                                                       const struct Parser<A>::CFIInfoArray&)
+{
+       return parser.tentativeDefinitionCount();
+}
+
+template <typename A>
+uint32_t TentativeDefinitionSection<A>::appendAtoms(class Parser<A>& parser, uint8_t* p, 
+                                                                                                               struct Parser<A>::LabelAndCFIBreakIterator& it, 
+                                                                                                               const struct Parser<A>::CFIInfoArray&)
+{
+       this->_beginAtoms = (Atom<A>*)p;
+       uint32_t count = 0;
+       for (uint32_t i=parser.undefinedStartIndex(); i < parser.undefinedEndIndex(); ++i) {
+               const macho_nlist<P>& sym =     parser.symbolFromIndex(i);
+               if ( ((sym.n_type() & N_TYPE) == N_UNDF) && (sym.n_value() != 0) ) {
+                       uint64_t size = sym.n_value();
+                       uint8_t alignP2 = GET_COMM_ALIGN(sym.n_desc());
+                       if ( alignP2 == 0 ) {
+                               // common symbols align to their size
+                               // that is, a 4-byte common aligns to 4-bytes
+                               // if this size is not a power of two, 
+                               // then round up to the next power of two
+                               alignP2 = 63 - (uint8_t)__builtin_clzll(size);
+                               if ( size != (1ULL << alignP2) )
+                                       ++alignP2;
+                       }
+                       // limit alignment of extremely large commons to 2^15 bytes (8-page)
+                       if ( alignP2 > 12 )
+                               alignP2 = 12;
+                       Atom<A>* allocatedSpace = (Atom<A>*)p;
+                       new (allocatedSpace) Atom<A>(*this, parser.nameFromSymbol(sym), (pint_t)ULLONG_MAX, size,
+                                                                               ld::Atom::definitionTentative,  ld::Atom::combineByName, 
+                                                                               parser.scopeFromSymbol(sym), ld::Atom::typeZeroFill, ld::Atom::symbolTableIn, 
+                                                                               parser.dontDeadStripFromSymbol(sym), false, false, ld::Atom::Alignment(alignP2) );
+                       p += sizeof(Atom<A>);
+                       ++count;
+               }
+       }
+       this->_endAtoms = (Atom<A>*)p;
+       return count;
+}
+
+
+template <typename A>
+uint32_t AbsoluteSymbolSection<A>::computeAtomCount(class Parser<A>& parser, 
+                                                                                                                       struct Parser<A>::LabelAndCFIBreakIterator& it, 
+                                                                                                                       const struct Parser<A>::CFIInfoArray&)
+{
+       return parser.absoluteSymbolCount();
+}
+
+template <typename A>
+uint32_t AbsoluteSymbolSection<A>::appendAtoms(class Parser<A>& parser, uint8_t* p, 
+                                                                                                               struct Parser<A>::LabelAndCFIBreakIterator& it, 
+                                                                                                               const struct Parser<A>::CFIInfoArray&)
+{
+       this->_beginAtoms = (Atom<A>*)p;
+       uint32_t count = 0;
+       for (uint32_t i=0; i < parser.symbolCount(); ++i) {
+               const macho_nlist<P>& sym =     parser.symbolFromIndex(i);
+               if ( (sym.n_type() & N_TYPE) != N_ABS )
+                       continue;
+               const char* absName = parser.nameFromSymbol(sym);
+               // ignore .objc_class_name_* symbols 
+               if ( strncmp(absName, ".objc_class_name_", 17) == 0 )
+                       continue;
+               // ignore .objc_class_name_* symbols 
+               if ( strncmp(absName, ".objc_category_name_", 20) == 0 )
+                       continue;
+               // ignore empty *.eh symbols
+               if ( strcmp(&absName[strlen(absName)-3], ".eh") == 0 )
+                       continue;
+
+               Atom<A>* allocatedSpace = (Atom<A>*)p;
+               new (allocatedSpace) Atom<A>(*this, parser, sym, 0);
+               p += sizeof(Atom<A>);
+               ++count;
+       }
+       this->_endAtoms = (Atom<A>*)p;
+       return count;
+}
+
+template <typename A>
+Atom<A>* AbsoluteSymbolSection<A>::findAbsAtomForValue(typename A::P::uint_t value)
+{
+       Atom<A>* end = this->_endAtoms;
+       for(Atom<A>* p = this->_beginAtoms; p < end; ++p) {
+               if ( p->_objAddress == value )  
+                       return p;
+       }
+       return NULL;
+}
+
+
+template <typename A>
+uint32_t Parser<A>::indirectSymbol(uint32_t indirectIndex)
+{
+       if ( indirectIndex >= _indirectTableCount )
+               throw "indirect symbol index out of range";
+       return E::get32(_indirectTable[indirectIndex]);
+}
+
+template <typename A>
+const macho_nlist<typename A::P>& Parser<A>::symbolFromIndex(uint32_t index)
+{
+       if ( index > _symbolCount )
+               throw "symbol index out of range";
+       return _symbols[index];
+}
+
+template <typename A>
+const macho_section<typename A::P>*    Parser<A>::machOSectionFromSectionIndex(uint32_t index)
+{
+       if ( index >= _machOSectionsCount )
+               throw "section index out of range";
+       return &_sectionsStart[index];
+}
+
+template <typename A>
+uint32_t Parser<A>::symbolIndexFromIndirectSectionAddress(pint_t addr, const macho_section<P>* sect)
+{
+       uint32_t elementSize = 0;
+       switch ( sect->flags() & SECTION_TYPE ) {
+               case S_SYMBOL_STUBS:
+                       elementSize = sect->reserved2();
+                       break;
+               case S_LAZY_SYMBOL_POINTERS:
+               case S_NON_LAZY_SYMBOL_POINTERS:
+                       elementSize = sizeof(pint_t);
+                       break;
+               default:
+                       throw "section does not use inirect symbol table";
+       }       
+       uint32_t indexInSection = (addr - sect->addr()) / elementSize;
+       uint32_t indexIntoIndirectTable = sect->reserved1() + indexInSection;
+       return this->indirectSymbol(indexIntoIndirectTable);
+}
+
+
+
+template <typename A>
+const char* Parser<A>::nameFromSymbol(const macho_nlist<P>& sym)
+{
+       return &_strings[sym.n_strx()];
+}
+
+template <typename A>
+ld::Atom::Scope Parser<A>::scopeFromSymbol(const macho_nlist<P>& sym)
+{
+       if ( (sym.n_type() & N_EXT) == 0 )
+               return ld::Atom::scopeTranslationUnit;
+       else if ( (sym.n_type() & N_PEXT) != 0 )
+               return ld::Atom::scopeLinkageUnit;
+       else if ( this->nameFromSymbol(sym)[0] == 'l' ) // since all 'l' symbols will be remove, don't make them global
+               return ld::Atom::scopeLinkageUnit;
+       else
+               return ld::Atom::scopeGlobal;
+}
+
+template <typename A>
+ld::Atom::Definition Parser<A>::definitionFromSymbol(const macho_nlist<P>& sym)
+{
+       switch ( sym.n_type() & N_TYPE ) {
+               case N_ABS:
+                       return ld::Atom::definitionAbsolute;
+               case N_SECT:
+                       return ld::Atom::definitionRegular;
+               case N_UNDF:
+                       if ( sym.n_value() != 0 ) 
+                               return ld::Atom::definitionTentative;
+       }
+       throw "definitionFromSymbol() bad symbol";
+}
+
+template <typename A>
+ld::Atom::Combine Parser<A>::combineFromSymbol(const macho_nlist<P>& sym)
+{
+       if ( sym.n_desc() & N_WEAK_DEF ) 
+               return ld::Atom::combineByName;
+       else
+               return ld::Atom::combineNever;
+}
+
+
+template <typename A>
+ld::Atom::SymbolTableInclusion Parser<A>::inclusionFromSymbol(const macho_nlist<P>& sym)
+{
+       const char* symbolName = nameFromSymbol(sym);
+       // labels beginning with 'l' (lowercase ell) are automatically removed in final linked images <rdar://problem/4571042>
+       // labels beginning with 'L' should have been stripped by the assembler, so are stripped now
+       if ( sym.n_desc() & REFERENCED_DYNAMICALLY ) 
+               return ld::Atom::symbolTableInAndNeverStrip;
+       else if ( symbolName[0] == 'l' )
+               return ld::Atom::symbolTableNotInFinalLinkedImages;
+       else if ( symbolName[0] == 'L' )
+               return ld::Atom::symbolTableNotIn;
+       else
+               return ld::Atom::symbolTableIn;
+}
+
+template <typename A>
+bool Parser<A>::dontDeadStripFromSymbol(const macho_nlist<P>& sym)
+{
+       return ( (sym.n_desc() & (N_NO_DEAD_STRIP|REFERENCED_DYNAMICALLY)) != 0 );
+}
+
+template <typename A>
+bool Parser<A>::isThumbFromSymbol(const macho_nlist<P>& sym)
+{
+       return ( sym.n_desc() & N_ARM_THUMB_DEF );
+}
+
+template <typename A>
+bool Parser<A>::weakImportFromSymbol(const macho_nlist<P>& sym)
+{
+       return ( ((sym.n_type() & N_TYPE) == N_UNDF) && ((sym.n_desc() & N_WEAK_REF) != 0) );
+}
+
+template <typename A>
+bool Parser<A>::resolverFromSymbol(const macho_nlist<P>& sym)
+{
+       return ( sym.n_desc() & N_SYMBOL_RESOLVER );
+}
+
+
+/* Skip over a LEB128 value (signed or unsigned).  */
+static void
+skip_leb128 (const uint8_t ** offset, const uint8_t * end)
+{
+  while (*offset != end && **offset >= 0x80)
+    (*offset)++;
+  if (*offset != end)
+    (*offset)++;
+}
+
+/* Read a ULEB128 into a 64-bit word.  Return (uint64_t)-1 on overflow
+   or error.  On overflow, skip past the rest of the uleb128.  */
+static uint64_t
+read_uleb128 (const uint8_t ** offset, const uint8_t * end)
+{
+  uint64_t result = 0;
+  int bit = 0;
+
+  do  {
+    uint64_t b;
+
+    if (*offset == end)
+      return (uint64_t) -1;
+
+    b = **offset & 0x7f;
+
+    if (bit >= 64 || b << bit >> bit != b)
+      result = (uint64_t) -1;
+    else
+      result |= b << bit, bit += 7;
+  } while (*(*offset)++ >= 0x80);
+  return result;
+}
+
+
+/* Skip over a DWARF attribute of form FORM.  */
+template <typename A>
+bool Parser<A>::skip_form(const uint8_t ** offset, const uint8_t * end, uint64_t form,
+                                                       uint8_t addr_size, bool dwarf64)
+{
+  int64_t sz=0;
+
+  switch (form)
+    {
+    case DW_FORM_addr:
+      sz = addr_size;
+      break;
+
+    case DW_FORM_block2:
+      if (end - *offset < 2)
+       return false;
+      sz = 2 + A::P::E::get16(*(uint16_t*)offset);
+      break;
+
+    case DW_FORM_block4:
+      if (end - *offset < 4)
+       return false;
+      sz = 2 + A::P::E::get32(*(uint32_t*)offset);
+      break;
+
+    case DW_FORM_data2:
+    case DW_FORM_ref2:
+      sz = 2;
+      break;
+
+    case DW_FORM_data4:
+    case DW_FORM_ref4:
+      sz = 4;
+      break;
+
+    case DW_FORM_data8:
+    case DW_FORM_ref8:
+      sz = 8;
+      break;
+
+    case DW_FORM_string:
+      while (*offset != end && **offset)
+       ++*offset;
+    case DW_FORM_data1:
+    case DW_FORM_flag:
+    case DW_FORM_ref1:
+      sz = 1;
+      break;
+
+    case DW_FORM_block:
+      sz = read_uleb128 (offset, end);
+      break;
+
+    case DW_FORM_block1:
+      if (*offset == end)
+       return false;
+      sz = 1 + **offset;
+      break;
+
+    case DW_FORM_sdata:
+    case DW_FORM_udata:
+    case DW_FORM_ref_udata:
+      skip_leb128 (offset, end);
+      return true;
+
+    case DW_FORM_strp:
+    case DW_FORM_ref_addr:
+      sz = 4;
+      break;
+
+    default:
+      return false;
+    }
+  if (end - *offset < sz)
+    return false;
+  *offset += sz;
+  return true;
+}
+
+
+template <typename A>
+const char* Parser<A>::getDwarfString(uint64_t form, const uint8_t* p)
+{
+       if ( form == DW_FORM_string )
+               return (const char*)p;
+       else if ( form == DW_FORM_strp ) {
+               uint32_t offset = E::get32(*((uint32_t*)p));
+               const char* dwarfStrings = (char*)_file->fileContent() + _file->_dwarfDebugStringSect->offset();
+               if ( offset > _file->_dwarfDebugStringSect->size() ) {
+                       warning("unknown dwarf DW_FORM_strp (offset=0x%08X) is too big in %s\n", offset, this->_path);
+                       return NULL;
+               }
+               return &dwarfStrings[offset];
+       }
+       warning("unknown dwarf string encoding (form=%lld) in %s\n", form, this->_path);
+       return NULL;
+}
+
+
+template <typename A>
+struct AtomAndLineInfo {
+       Atom<A>*                        atom;
+       ld::Atom::LineInfo      info;
+};
+
+
+// <rdar://problem/5591394> Add support to ld64 for N_FUN stabs when used for symbolic constants
+// Returns whether a stabStr belonging to an N_FUN stab represents a
+// symbolic constant rather than a function
+template <typename A>
+bool Parser<A>::isConstFunStabs(const char *stabStr)
+{
+       const char* colon;
+       // N_FUN can be used for both constants and for functions. In case it's a constant,
+       // the format of the stabs string is "symname:c=<value>;"
+       // ':' cannot appear in the symbol name, except if it's an Objective-C method
+       // (in which case the symbol name starts with + or -, and then it's definitely
+       //  not a constant)
+       return (stabStr != NULL) && (stabStr[0] != '+') && (stabStr[0] != '-')
+                       && ((colon = strchr(stabStr, ':')) != NULL)
+                       && (colon[1] == 'c') && (colon[2] == '=');
+}
+
+
+template <typename A>
+void Parser<A>::parseDebugInfo()
+{
+       // check for dwarf __debug_info section
+       if ( _file->_dwarfDebugInfoSect == NULL ) {
+               // if no DWARF debug info, look for stabs
+               this->parseStabs();
+               return;
+       }
+       if ( _file->_dwarfDebugInfoSect->size() == 0 )
+               return;
+               
+       uint64_t stmtList;
+       if ( !read_comp_unit(&_file->_dwarfTranslationUnitFile, &_file->_dwarfTranslationUnitDir, &stmtList) ) {
+               // if can't parse dwarf, warn and give up
+               _file->_dwarfTranslationUnitFile = NULL;
+               _file->_dwarfTranslationUnitDir = NULL;
+               warning("can't parse dwarf compilation unit info in %s", _path);
+               _file->_debugInfoKind = ld::relocatable::File::kDebugInfoNone;
+               return;
+       }
+       
+       // add line number info to atoms from dwarf
+       std::vector<AtomAndLineInfo<A> > entries;
+       entries.reserve(64);
+       if ( _file->_debugInfoKind == ld::relocatable::File::kDebugInfoDwarf ) {
+               // file with just data will have no __debug_line info
+               if ( (_file->_dwarfDebugLineSect != NULL) && (_file->_dwarfDebugLineSect->size() != 0) ) {
+                       // validate stmt_list
+                       if ( (stmtList != (uint64_t)-1) && (stmtList < _file->_dwarfDebugLineSect->size()) ) {
+                               const uint8_t* debug_line = (uint8_t*)_file->fileContent() + _file->_dwarfDebugLineSect->offset();
+                               struct line_reader_data* lines = line_open(&debug_line[stmtList],
+                                                                                                               _file->_dwarfDebugLineSect->size() - stmtList, E::little_endian);
+                               struct line_info result;
+                               Atom<A>* curAtom = NULL;
+                               uint32_t curAtomOffset = 0;
+                               uint32_t curAtomAddress = 0;
+                               uint32_t curAtomSize = 0;
+                               std::map<uint32_t,const char*>  dwarfIndexToFile;
+                               if ( lines != NULL ) {
+                                       while ( line_next(lines, &result, line_stop_pc) ) {
+                                               //fprintf(stderr, "curAtom=%p, result.pc=0x%llX, result.line=%llu, result.end_of_sequence=%d,"
+                                               //                                " curAtomAddress=0x%X, curAtomSize=0x%X\n",
+                                               //              curAtom, result.pc, result.line, result.end_of_sequence, curAtomAddress, curAtomSize);
+                                               // work around weird debug line table compiler generates if no functions in __text section
+                                               if ( (curAtom == NULL) && (result.pc == 0) && result.end_of_sequence && (result.file == 1))
+                                                       continue;
+                                               // for performance, see if in next pc is in current atom
+                                               if ( (curAtom != NULL) && (curAtomAddress <= result.pc) && (result.pc < (curAtomAddress+curAtomSize)) ) {
+                                                       curAtomOffset = result.pc - curAtomAddress;
+                                               }
+                                               // or pc at end of current atom
+                                               else if ( result.end_of_sequence && (curAtom != NULL) && (result.pc == (curAtomAddress+curAtomSize)) ) {
+                                                       curAtomOffset = result.pc - curAtomAddress;
+                                               }
+                                               // or only one function that is a one line function
+                                               else if ( result.end_of_sequence && (curAtom == NULL) && (this->findAtomByAddress(0) != NULL) && (result.pc == this->findAtomByAddress(0)->size()) ) {
+                                                       curAtom                 = this->findAtomByAddress(0);
+                                                       curAtomOffset   = result.pc - curAtom->objectAddress();
+                                                       curAtomAddress  = curAtom->objectAddress();
+                                                       curAtomSize             = curAtom->size();
+                                               }
+                                               else {
+                                                       // do slow look up of atom by address
+                                                       try {
+                                                               curAtom = this->findAtomByAddress(result.pc);
+                                                       }
+                                                       catch (...) {
+                                                               // in case of bug in debug info, don't abort link, just limp on
+                                                               curAtom = NULL;
+                                                       }
+                                                       if ( curAtom == NULL )
+                                                               break; // file has line info but no functions
+                                                       if ( result.end_of_sequence && (curAtomAddress+curAtomSize < result.pc) ) {     
+                                                               // a one line function can be returned by line_next() as one entry with pc at end of blob
+                                                               // look for alt atom starting at end of previous atom
+                                                               uint32_t previousEnd = curAtomAddress+curAtomSize;
+                                                               Atom<A>* alt = this->findAtomByAddressOrNullIfStub(previousEnd);
+                                                               if ( alt == NULL )
+                                                                       continue; // ignore spurious debug info for stubs
+                                                               if ( result.pc <= alt->objectAddress() + alt->size() ) {
+                                                                       curAtom                 = alt;
+                                                                       curAtomOffset   = result.pc - alt->objectAddress();
+                                                                       curAtomAddress  = alt->objectAddress();
+                                                                       curAtomSize             = alt->size();
+                                                               }
+                                                               else {
+                                                                       curAtomOffset   = result.pc - curAtom->objectAddress();
+                                                                       curAtomAddress  = curAtom->objectAddress();
+                                                                       curAtomSize             = curAtom->size();
+                                                               }
+                                                       }
+                                                       else {
+                                                               curAtomOffset   = result.pc - curAtom->objectAddress();
+                                                               curAtomAddress  = curAtom->objectAddress();
+                                                               curAtomSize             = curAtom->size();
+                                                       }
+                                               }
+                                               const char* filename;
+                                               std::map<uint32_t,const char*>::iterator pos = dwarfIndexToFile.find(result.file);
+                                               if ( pos == dwarfIndexToFile.end() ) {
+                                                       filename = line_file(lines, result.file);
+                                                       dwarfIndexToFile[result.file] = filename;
+                                               }
+                                               else {
+                                                       filename = pos->second;
+                                               }
+                                               // only record for ~8000 line info records per function
+                                               if ( curAtom->roomForMoreLineInfoCount() ) {
+                                                       AtomAndLineInfo<A> entry;
+                                                       entry.atom = curAtom;
+                                                       entry.info.atomOffset = curAtomOffset;
+                                                       entry.info.fileName = filename;
+                                                       entry.info.lineNumber = result.line;
+                                                       //fprintf(stderr, "addr=0x%08llX, line=%lld, file=%s, atom=%s, atom.size=0x%X, end=%d\n", 
+                                                       //              result.pc, result.line, filename, curAtom->name(), curAtomSize, result.end_of_sequence);
+                                                       entries.push_back(entry);
+                                                       curAtom->incrementLineInfoCount();
+                                               }
+                                               if ( result.end_of_sequence ) {
+                                                       curAtom = NULL;
+                                               }
+                                       }
+                                       line_free(lines);
+                               }
+                       }
+               }
+       }
+               
+       // assign line info start offset for each atom
+       uint8_t* p = _file->_atomsArray;
+       uint32_t liOffset = 0;
+       for(int i=_file->_atomsArrayCount; i > 0; --i) {
+               Atom<A>* atom = (Atom<A>*)p;
+               atom->_lineInfoStartIndex = liOffset;
+               liOffset += atom->_lineInfoCount;
+               atom->_lineInfoCount = 0;
+               p += sizeof(Atom<A>);
+       }
+       assert(liOffset == entries.size());
+       _file->_lineInfos.reserve(liOffset);
+
+       // copy each line info for each atom 
+       for (typename std::vector<AtomAndLineInfo<A> >::iterator it = entries.begin(); it != entries.end(); ++it) {
+               uint32_t slot = it->atom->_lineInfoStartIndex + it->atom->_lineInfoCount;
+               _file->_lineInfos[slot] = it->info;
+               it->atom->_lineInfoCount++;
+       }
+       
+       // done with temp vector
+       entries.clear();
+}
+
+template <typename A>
+void Parser<A>::parseStabs()
+{
+       // scan symbol table for stabs entries
+       Atom<A>* currentAtom = NULL;
+       pint_t currentAtomAddress = 0;
+       enum { start, inBeginEnd, inFun } state = start;
+       for (uint32_t symbolIndex = 0; symbolIndex < _symbolCount; ++symbolIndex ) {
+               const macho_nlist<P>& sym = this->symbolFromIndex(symbolIndex);
+               bool useStab = true;
+               uint8_t type = sym.n_type();
+               const char* symString = (sym.n_strx() != 0) ? this->nameFromSymbol(sym) : NULL;
+               if ( (type & N_STAB) != 0 ) {
+                       _file->_debugInfoKind =  (_hasUUID ? ld::relocatable::File::kDebugInfoStabsUUID : ld::relocatable::File::kDebugInfoStabs);
+                       ld::relocatable::File::Stab stab;
+                       stab.atom       = NULL;
+                       stab.type       = type;
+                       stab.other      = sym.n_sect();
+                       stab.desc       = sym.n_desc();
+                       stab.value      = sym.n_value();
+                       stab.string = NULL;
+                       switch (state) {
+                               case start:
+                                       switch (type) {
+                                               case N_BNSYM:
+                                                       // beginning of function block
+                                                       state = inBeginEnd;
+                                                       // fall into case to lookup atom by addresss
+                                               case N_LCSYM:
+                                               case N_STSYM:
+                                                       currentAtomAddress = sym.n_value();
+                                                       currentAtom = this->findAtomByAddress(currentAtomAddress);
+                                                       if ( currentAtom != NULL ) {
+                                                               stab.atom = currentAtom;
+                                                               stab.string = symString;
+                                                       }
+                                                       else {
+                                                               fprintf(stderr, "can't find atom for stabs BNSYM at %08llX in %s",
+                                                                       (uint64_t)sym.n_value(), _path);
+                                                       }
+                                                       break;
+                                               case N_SO:
+                                               case N_OSO:
+                                               case N_OPT:
+                                               case N_LSYM:
+                                               case N_RSYM:
+                                               case N_PSYM:
+                                                       // not associated with an atom, just copy
+                                                       stab.string = symString;
+                                                       break;
+                                               case N_GSYM:
+                                               {
+                                                       // n_value field is NOT atom address ;-(
+                                                       // need to find atom by name match
+                                                       const char* colon = strchr(symString, ':');
+                                                       if ( colon != NULL ) {
+                                                               // build underscore leading name
+                                                               int nameLen = colon - symString;
+                                                               char symName[nameLen+2];
+                                                               strlcpy(&symName[1], symString, nameLen+1);
+                                                               symName[0] = '_';
+                                                               symName[nameLen+1] = '\0';
+                                                               currentAtom = this->findAtomByName(symName);
+                                                               if ( currentAtom != NULL ) {
+                                                                       stab.atom = currentAtom;
+                                                                       stab.string = symString;
+                                                               }
+                                                       }
+                                                       else {
+                                                               // might be a debug-note without trailing :G()
+                                                               currentAtom = this->findAtomByName(symString);
+                                                               if ( currentAtom != NULL ) {
+                                                                       stab.atom = currentAtom;
+                                                                       stab.string = symString;
+                                                               }
+                                                       }
+                                                       if ( stab.atom == NULL ) {
+                                                               // ld_classic added bogus GSYM stabs for old style dtrace probes
+                                                               if ( (strncmp(symString, "__dtrace_probe$", 15) != 0) )
+                                                                       warning("can't find atom for N_GSYM stabs %s in %s", symString, _path);
+                                                               useStab = false;
+                                                       }
+                                                       break;
+                                               }
+                                               case N_FUN:
+                                                       if ( isConstFunStabs(symString) ) {
+                                                               // constant not associated with a function
+                                                               stab.string = symString;
+                                                       }
+                                                       else {
+                                                               // old style stabs without BNSYM
+                                                               state = inFun;
+                                                               currentAtomAddress = sym.n_value();
+                                                               currentAtom = this->findAtomByAddress(currentAtomAddress);
+                                                               if ( currentAtom != NULL ) {
+                                                                       stab.atom = currentAtom;
+                                                                       stab.string = symString;
+                                                               }
+                                                               else {
+                                                                       warning("can't find atom for stabs FUN at %08llX in %s",
+                                                                               (uint64_t)currentAtomAddress, _path);
+                                                               }
+                                                       }
+                                                       break;
+                                               case N_SOL:
+                                               case N_SLINE:
+                                                       stab.string = symString;
+                                                       // old stabs
+                                                       break;
+                                               case N_BINCL:
+                                               case N_EINCL:
+                                               case N_EXCL:
+                                                       stab.string = symString;
+                                                       // -gfull built .o file
+                                                       break;
+                                               default:
+                                                       warning("unknown stabs type 0x%X in %s", type, _path);
+                                       }
+                                       break;
+                               case inBeginEnd:
+                                       stab.atom = currentAtom;
+                                       switch (type) {
+                                               case N_ENSYM:
+                                                       state = start;
+                                                       currentAtom = NULL;
+                                                       break;
+                                               case N_LCSYM:
+                                               case N_STSYM:
+                                               {
+                                                       Atom<A>* nestedAtom = this->findAtomByAddress(sym.n_value());
+                                                       if ( nestedAtom != NULL ) {
+                                                               stab.atom = nestedAtom;
+                                                               stab.string = symString;
+                                                       }
+                                                       else {
+                                                               warning("can't find atom for stabs 0x%X at %08llX in %s",
+                                                                       type, (uint64_t)sym.n_value(), _path);
+                                                       }
+                                                       break;
+                                               }
+                                               case N_LBRAC:
+                                               case N_RBRAC:
+                                               case N_SLINE:
+                                                       // adjust value to be offset in atom
+                                                       stab.value -= currentAtomAddress;
+                                               default:
+                                                       stab.string = symString;
+                                                       break;
+                                       }
+                                       break;
+                               case inFun:
+                                       switch (type) {
+                                               case N_FUN:
+                                                       if ( isConstFunStabs(symString) ) {
+                                                               stab.atom = currentAtom;
+                                                               stab.string = symString;
+                                                       }
+                                                       else {
+                                                               if ( sym.n_sect() != 0 ) {
+                                                                       // found another start stab, must be really old stabs...
+                                                                       currentAtomAddress = sym.n_value();
+                                                                       currentAtom = this->findAtomByAddress(currentAtomAddress);
+                                                                       if ( currentAtom != NULL ) {
+                                                                               stab.atom = currentAtom;
+                                                                               stab.string = symString;
+                                                                       }
+                                                                       else {
+                                                                               warning("can't find atom for stabs FUN at %08llX in %s",
+                                                                                       (uint64_t)currentAtomAddress, _path);
+                                                                       }
+                                                               }
+                                                               else {
+                                                                       // found ending stab, switch back to start state
+                                                                       stab.string = symString;
+                                                                       stab.atom = currentAtom;
+                                                                       state = start;
+                                                                       currentAtom = NULL;
+                                                               }
+                                                       }
+                                                       break;
+                                               case N_LBRAC:
+                                               case N_RBRAC:
+                                               case N_SLINE:
+                                                       // adjust value to be offset in atom
+                                                       stab.value -= currentAtomAddress;
+                                                       stab.atom = currentAtom;
+                                                       break;
+                                               case N_SO:
+                                                       stab.string = symString;
+                                                       state = start;
+                                                       break;
+                                               default:
+                                                       stab.atom = currentAtom;
+                                                       stab.string = symString;
+                                                       break;
+                                       }
+                                       break;
+                       }
+                       // add to list of stabs for this .o file
+                       if ( useStab )
+                               _file->_stabs.push_back(stab);
+               }
+       }
+}
+
+
+
+// Look at the compilation unit DIE and determine
+// its NAME, compilation directory (in COMP_DIR) and its
+// line number information offset (in STMT_LIST).  NAME and COMP_DIR
+// may be NULL (especially COMP_DIR) if they are not in the .o file;
+// STMT_LIST will be (uint64_t) -1.
+//
+// At present this assumes that there's only one compilation unit DIE.
+//
+template <typename A>
+bool Parser<A>::read_comp_unit(const char ** name, const char ** comp_dir,
+                                                       uint64_t *stmt_list)
+{
+       const uint8_t * debug_info;
+       const uint8_t * debug_abbrev;
+       const uint8_t * di;
+       const uint8_t * da;
+       const uint8_t * end;
+       const uint8_t * enda;
+       uint64_t sz;
+       uint16_t vers;
+       uint64_t abbrev_base;
+       uint64_t abbrev;
+       uint8_t address_size;
+       bool dwarf64;
+
+       *name = NULL;
+       *comp_dir = NULL;
+       *stmt_list = (uint64_t) -1;
+
+       if ( (_file->_dwarfDebugInfoSect == NULL) || (_file->_dwarfDebugAbbrevSect == NULL) )
+               return false;
+
+       debug_info = (uint8_t*)_file->fileContent() + _file->_dwarfDebugInfoSect->offset();
+       debug_abbrev = (uint8_t*)_file->fileContent() + _file->_dwarfDebugAbbrevSect->offset();
+       di = debug_info;
+
+       if (_file->_dwarfDebugInfoSect->size() < 12)
+               /* Too small to be a real debug_info section.  */
+               return false;
+       sz = A::P::E::get32(*(uint32_t*)di);
+       di += 4;
+       dwarf64 = sz == 0xffffffff;
+       if (dwarf64)
+               sz = A::P::E::get64(*(uint64_t*)di), di += 8;
+       else if (sz > 0xffffff00)
+               /* Unknown dwarf format.  */
+               return false;
+
+       /* Verify claimed size.  */
+       if (sz + (di - debug_info) > _file->_dwarfDebugInfoSect->size() || sz <= (dwarf64 ? 23 : 11))
+               return false;
+
+       vers = A::P::E::get16(*(uint16_t*)di);
+       if (vers < 2 || vers > 3)
+       /* DWARF version wrong for this code.
+          Chances are we could continue anyway, but we don't know for sure.  */
+               return false;
+       di += 2;
+
+       /* Find the debug_abbrev section.  */
+       abbrev_base = dwarf64 ? A::P::E::get64(*(uint64_t*)di) : A::P::E::get32(*(uint32_t*)di);
+       di += dwarf64 ? 8 : 4;
+
+       if (abbrev_base > _file->_dwarfDebugAbbrevSect->size())
+               return false;
+       da = debug_abbrev + abbrev_base;
+       enda = debug_abbrev + _file->_dwarfDebugAbbrevSect->size();
+
+       address_size = *di++;
+
+       /* Find the abbrev number we're looking for.  */
+       end = di + sz;
+       abbrev = read_uleb128 (&di, end);
+       if (abbrev == (uint64_t) -1)
+               return false;
+
+       /* Skip through the debug_abbrev section looking for that abbrev.  */
+       for (;;)
+       {
+               uint64_t this_abbrev = read_uleb128 (&da, enda);
+               uint64_t attr;
+
+               if (this_abbrev == abbrev)
+                       /* This is almost always taken.  */
+                       break;
+               skip_leb128 (&da, enda); /* Skip the tag.  */
+               if (da == enda)
+                       return false;
+               da++;  /* Skip the DW_CHILDREN_* value.  */
+
+               do {
+                       attr = read_uleb128 (&da, enda);
+                       skip_leb128 (&da, enda);
+               } while (attr != 0 && attr != (uint64_t) -1);
+               if (attr != 0)
+                       return false;
+       }
+
+       /* Check that the abbrev is one for a DW_TAG_compile_unit.  */
+       if (read_uleb128 (&da, enda) != DW_TAG_compile_unit)
+       return false;
+       if (da == enda)
+       return false;
+       da++;  /* Skip the DW_CHILDREN_* value.  */
+
+       /* Now, go through the DIE looking for DW_AT_name,
+        DW_AT_comp_dir, and DW_AT_stmt_list.  */
+       for (;;)
+       {
+               uint64_t attr = read_uleb128 (&da, enda);
+               uint64_t form = read_uleb128 (&da, enda);
+
+               if (attr == (uint64_t) -1)
+                       return false;
+               else if (attr == 0)
+                       return true;
+
+               if (form == DW_FORM_indirect)
+                       form = read_uleb128 (&di, end);
+
+               if (attr == DW_AT_name)
+                       *name = getDwarfString(form, di);
+               else if (attr == DW_AT_comp_dir)
+                       *comp_dir = getDwarfString(form, di);
+               else if (attr == DW_AT_stmt_list && form == DW_FORM_data4)
+                       *stmt_list = A::P::E::get32(*(uint32_t*)di);
+               else if (attr == DW_AT_stmt_list && form == DW_FORM_data8)
+                       *stmt_list = A::P::E::get64(*(uint64_t*)di);
+               if (! skip_form (&di, end, form, address_size, dwarf64))
+                       return false;
+       }
+}
+
+
+
+template <typename A>
+File<A>::~File()
+{
+       free(_sectionsArray);
+       free(_atomsArray);
+}
+
+template <typename A>
+bool File<A>::translationUnitSource(const char** dir, const char** name) const
+{
+       if ( _debugInfoKind == ld::relocatable::File::kDebugInfoDwarf ) {
+               *dir = _dwarfTranslationUnitDir;
+               *name = _dwarfTranslationUnitFile;
+               return (_dwarfTranslationUnitFile != NULL);
+       }
+       return false;
+}
+
+       
+
+template <typename A>
+bool File<A>::forEachAtom(ld::File::AtomHandler& handler) const
+{
+       handler.doFile(*this);
+       uint8_t* p = _atomsArray;
+       for(int i=_atomsArrayCount; i > 0; --i) {
+               handler.doAtom(*((Atom<A>*)p));
+               p += sizeof(Atom<A>);
+       }
+       return (_atomsArrayCount != 0);
+}
+
+template <typename A>
+const char* Section<A>::makeSegmentName(const macho_section<typename A::P>* sect)
+{
+       // mach-o section record only has room for 16-byte seg/sect names
+       // so a 16-byte name has no trailing zero
+       const char* name = sect->segname();
+       if ( strlen(name) < 16 ) 
+               return name;
+       char* tmp = new char[17];
+       strlcpy(tmp, name, 17);
+       return tmp;
+}
+
+template <typename A>
+const char* Section<A>::makeSectionName(const macho_section<typename A::P>* sect)
+{
+       const char* name = sect->sectname();
+       if ( strlen(name) < 16 ) 
+               return name;
+               
+       // special case common long section names so we don't have to malloc
+       if ( strncmp(sect->sectname(), "__objc_classrefs", 16) == 0 )
+               return "__objc_classrefs";
+       if ( strncmp(sect->sectname(), "__objc_classlist", 16) == 0 )
+               return "__objc_classlist";
+       if ( strncmp(sect->sectname(), "__objc_nlclslist", 16) == 0 )
+               return "__objc_nlclslist";
+       if ( strncmp(sect->sectname(), "__objc_nlcatlist", 16) == 0 )
+               return "__objc_nlcatlist";
+       if ( strncmp(sect->sectname(), "__objc_protolist", 16) == 0 )
+               return "__objc_protolist";
+       if ( strncmp(sect->sectname(), "__objc_protorefs", 16) == 0 )
+               return "__objc_protorefs";
+       if ( strncmp(sect->sectname(), "__objc_superrefs", 16) == 0 )
+               return "__objc_superrefs";
+       if ( strncmp(sect->sectname(), "__objc_imageinfo", 16) == 0 )
+               return "__objc_imageinfo";
+       if ( strncmp(sect->sectname(), "__objc_stringobj", 16) == 0 )
+               return "__objc_stringobj";
+       if ( strncmp(sect->sectname(), "__gcc_except_tab", 16) == 0 )
+               return "__gcc_except_tab";
+
+       char* tmp = new char[17];
+       strlcpy(tmp, name, 17);
+       return tmp;
+}
+
+template <typename A>
+bool Section<A>::readable(const macho_section<typename A::P>* sect)
+{
+       return true;
+}
+
+template <typename A>
+bool Section<A>::writable(const macho_section<typename A::P>* sect)
+{
+       // mach-o .o files do not contain segment permissions
+       // we just know TEXT is special
+       return ( strcmp(sect->segname(), "__TEXT") != 0 );
+}
+
+template <typename A>
+bool Section<A>::exectuable(const macho_section<typename A::P>* sect)
+{
+       // mach-o .o files do not contain segment permissions
+       // we just know TEXT is special
+       return ( strcmp(sect->segname(), "__TEXT") == 0 );
+}
+
+
+template <typename A>
+ld::Section::Type Section<A>::sectionType(const macho_section<typename A::P>* sect)
+{
+       switch ( sect->flags() & SECTION_TYPE ) {
+               case S_ZEROFILL:
+                       return ld::Section::typeZeroFill;
+               case S_CSTRING_LITERALS:
+                       if ( (strcmp(sect->sectname(), "__cstring") == 0) && (strcmp(sect->segname(), "__TEXT") == 0) )
+                               return ld::Section::typeCString;
+                       else
+                               return ld::Section::typeNonStdCString;
+               case S_4BYTE_LITERALS:
+                       return ld::Section::typeLiteral4;
+               case S_8BYTE_LITERALS:
+                       return ld::Section::typeLiteral8;
+               case S_LITERAL_POINTERS:
+                       return ld::Section::typeCStringPointer;
+               case S_NON_LAZY_SYMBOL_POINTERS:
+                       return ld::Section::typeNonLazyPointer;
+               case S_LAZY_SYMBOL_POINTERS:
+                       return ld::Section::typeLazyPointer;
+               case S_SYMBOL_STUBS:
+                       return ld::Section::typeStub;
+               case S_MOD_INIT_FUNC_POINTERS:
+                       return ld::Section::typeInitializerPointers;
+               case S_MOD_TERM_FUNC_POINTERS:
+                       return ld::Section::typeTerminatorPointers;
+               case S_INTERPOSING:
+                       return ld::Section::typeUnclassified;
+               case S_16BYTE_LITERALS:
+                       return ld::Section::typeLiteral16;
+               case S_REGULAR:
+               case S_COALESCED:
+                       if ( sect->flags() & S_ATTR_PURE_INSTRUCTIONS ) {
+                               return ld::Section::typeCode;
+                       }
+                       else if ( strcmp(sect->segname(), "__TEXT") == 0 ) {
+                               if ( strcmp(sect->sectname(), "__eh_frame") == 0 ) 
+                                       return ld::Section::typeCFI;
+                               else if ( strcmp(sect->sectname(), "__ustring") == 0 )
+                                       return ld::Section::typeUTF16Strings;
+                               else if ( strcmp(sect->sectname(), "__textcoal_nt") == 0 )
+                                       return ld::Section::typeCode;
+                               else if ( strcmp(sect->sectname(), "__StaticInit") == 0 )
+                                       return ld::Section::typeCode;
+                       }
+                       else if ( strcmp(sect->segname(), "__DATA") == 0 ) {
+                               if ( strcmp(sect->sectname(), "__cfstring") == 0 ) 
+                                       return ld::Section::typeCFString;
+                               else if ( strcmp(sect->sectname(), "__dyld") == 0 )
+                                       return ld::Section::typeDyldInfo;
+                               else if ( strcmp(sect->sectname(), "__program_vars") == 0 )
+                                       return ld::Section::typeDyldInfo;
+                               else if ( strncmp(sect->sectname(), "__objc_classrefs", 16) == 0 )
+                                       return ld::Section::typeObjCClassRefs;
+                               else if ( strcmp(sect->sectname(), "__objc_catlist") == 0 )
+                                       return ld::Section::typeObjC2CategoryList;
+                       }
+                       else if ( strcmp(sect->segname(), "__OBJC") == 0 ) {
+                               if ( strcmp(sect->sectname(), "__class") == 0 ) 
+                                       return ld::Section::typeObjC1Classes;
+                       }
+                       break;
+               case S_THREAD_LOCAL_REGULAR:
+                       return ld::Section::typeTLVInitialValues;
+               case S_THREAD_LOCAL_ZEROFILL:
+                       return ld::Section::typeTLVZeroFill;
+               case S_THREAD_LOCAL_VARIABLES:
+                       return ld::Section::typeTLVDefs;
+               case S_THREAD_LOCAL_INIT_FUNCTION_POINTERS:
+                       return ld::Section::typeTLVInitializerPointers;
+       }
+       return ld::Section::typeUnclassified;
+}
+
+
+template <typename A>
+Atom<A>* Section<A>::findContentAtomByAddress(pint_t addr, class Atom<A>* start, class Atom<A>* end)
+{
+       // do a binary search of atom array
+       uint32_t atomCount = end - start;
+       Atom<A>* base = start;
+       for (uint32_t n = atomCount; n > 0; n /= 2) {
+               Atom<A>* pivot = &base[n/2];
+               pint_t atomStartAddr = pivot->_objAddress;
+               pint_t atomEndAddr = atomStartAddr + pivot->_size;
+               if ( atomStartAddr <= addr ) {
+                       // address in normal atom
+                       if (addr < atomEndAddr)
+                               return pivot;
+                       // address in "end" label (but not in alias)
+                       if ( (pivot->_size == 0) && (addr == atomEndAddr) && !pivot->isAlias() )
+                               return pivot;
+               }
+               if ( addr >= atomEndAddr ) {
+                       // key > pivot 
+                       // move base to atom after pivot
+                       base = &pivot[1];
+                       --n; 
+               }
+               else {
+                       // key < pivot 
+                       // keep same base
+               }
+       }
+       return NULL;
+}
+
+template <typename A>
+ld::Atom::Alignment Section<A>::alignmentForAddress(pint_t addr) 
+{ 
+       const uint32_t sectionAlignment = this->_machOSection->align();
+       return ld::Atom::Alignment(sectionAlignment, (addr % (1 << sectionAlignment)));
+}
+
+template <typename A>
+uint32_t Section<A>::sectionNum(class Parser<A>& parser) const 
+{ 
+       if ( _machOSection == NULL )
+               return 0;
+       else
+               return 1 + (this->_machOSection - parser.firstMachOSection());
+}
+
+// libunwind does not support ppc64
+template <> uint32_t CFISection<ppc64>::cfiCount() { return 0; }
+// arm does not have zero cost exceptions
+template <> uint32_t CFISection<arm>::cfiCount() { return 0; }
+
+template <typename A>
+uint32_t CFISection<A>::cfiCount()
+{
+       // create ObjectAddressSpace object for use by libunwind
+       OAS oas(*this, (uint8_t*)this->file().fileContent()+this->_machOSection->offset());
+       return libunwind::CFI_Parser<OAS>::getCFICount(oas, 
+                                                                               this->_machOSection->addr(), this->_machOSection->size());
+}
+
+template <typename A>
+void CFISection<A>::warnFunc(void* ref, uint64_t funcAddr, const char* msg)
+{
+       Parser<A>* parser = (Parser<A>*)ref;
+       if ( ! parser->convertUnwindInfo() ) 
+               return;
+       if ( funcAddr != CFI_INVALID_ADDRESS ) {
+               // atoms are not constructed yet, so scan symbol table for labels
+               const char* name = parser->scanSymbolTableForAddress(funcAddr);
+               warning("could not create compact unwind for %s: %s", name, msg);
+       }
+       else {
+               warning("could not create compact unwind: %s", msg);
+       }
+}
+
+template <>
+bool CFISection<x86_64>::needsRelocating()
+{
+       return true;
+}
+
+template <typename A>
+bool CFISection<A>::needsRelocating()
+{
+       return false;
+}
+
+template <>
+void CFISection<x86_64>::cfiParse(class Parser<x86_64>& parser, uint8_t* buffer, 
+                                                                       libunwind::CFI_Atom_Info<CFISection<x86_64>::OAS>::CFI_Atom_Info cfiArray[], 
+                                                                       uint32_t count)
+{
+       // copy __eh_frame data to buffer
+       memcpy(buffer, file().fileContent() + this->_machOSection->offset(), this->_machOSection->size());
+
+       // and apply relocations
+       const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)(file().fileContent() + this->_machOSection->reloff());
+       const macho_relocation_info<P>* relocsEnd = &relocs[this->_machOSection->nreloc()];
+       for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
+               uint64_t value = 0;
+               switch ( reloc->r_type() ) {
+                       case X86_64_RELOC_SUBTRACTOR:   
+                               value =  0 - parser.symbolFromIndex(reloc->r_symbolnum()).n_value();
+                               ++reloc;
+                               if ( reloc->r_extern() )
+                                       value += parser.symbolFromIndex(reloc->r_symbolnum()).n_value();
+                               break;
+                       case X86_64_RELOC_UNSIGNED:
+                               value = parser.symbolFromIndex(reloc->r_symbolnum()).n_value();
+                               break;
+                       case X86_64_RELOC_GOT:
+                               // this is used for the reference to the personality function in CIEs
+                               // store the symbol number of the personality function for later use as a Fixup
+                               value = reloc->r_symbolnum();
+                               break;
+                       default:
+                               fprintf(stderr, "CFISection::cfiParse() unexpected relocation type at r_address=0x%08X\n", reloc->r_address());
+                               break;
+               }
+               uint64_t*       p64;
+               uint32_t*       p32;
+               switch ( reloc->r_length() ) {
+                       case 3:
+                               p64 = (uint64_t*)&buffer[reloc->r_address()];
+                               E::set64(*p64, value + E::get64(*p64));
+                               break;
+                       case 2:
+                               p32 = (uint32_t*)&buffer[reloc->r_address()];
+                               E::set32(*p32, value + E::get32(*p32));
+                               break;
+                       default:
+                               fprintf(stderr, "CFISection::cfiParse() unexpected relocation size at r_address=0x%08X\n", reloc->r_address());
+                               break;
+               }
+       }
+       
+       
+       // create ObjectAddressSpace object for use by libunwind
+       OAS oas(*this, buffer);
+       
+       // use libuwind to parse __eh_frame data into array of CFI_Atom_Info
+       const char* msg;
+       msg = libunwind::DwarfInstructions<OAS, libunwind::Registers_x86_64>::parseCFIs(
+                                                       oas, this->_machOSection->addr(), this->_machOSection->size(), 
+                                                       cfiArray, count, (void*)&parser, warnFunc);
+       if ( msg != NULL ) 
+               throwf("malformed __eh_frame section: %s", msg);
+}
+
+template <>
+void CFISection<x86>::cfiParse(class Parser<x86>& parser, uint8_t* buffer, 
+                                                                       libunwind::CFI_Atom_Info<CFISection<x86>::OAS>::CFI_Atom_Info cfiArray[], 
+                                                                       uint32_t count)
+{
+       // create ObjectAddressSpace object for use by libunwind
+       OAS oas(*this, (uint8_t*)this->file().fileContent()+this->_machOSection->offset());
+       
+       // use libuwind to parse __eh_frame data into array of CFI_Atom_Info
+       const char* msg;
+       msg = libunwind::DwarfInstructions<OAS, libunwind::Registers_x86>::parseCFIs(
+                                                       oas, this->_machOSection->addr(), this->_machOSection->size(), 
+                                                       cfiArray, count, (void*)&parser, warnFunc);
+       if ( msg != NULL ) 
+               throwf("malformed __eh_frame section: %s", msg);
+}
+
+
+// need to change libunwind parseCFIs() to work for ppc
+template <>
+void CFISection<ppc>::cfiParse(class Parser<ppc>& parser, uint8_t* buffer, 
+                                                                       libunwind::CFI_Atom_Info<CFISection<ppc>::OAS>::CFI_Atom_Info cfiArray[], 
+                                                                       uint32_t count)
+{
+       // create ObjectAddressSpace object for use by libunwind
+       OAS oas(*this, (uint8_t*)this->file().fileContent()+this->_machOSection->offset());
+       
+       // use libuwind to parse __eh_frame data into array of CFI_Atom_Info
+       const char* msg;
+       msg = libunwind::DwarfInstructions<OAS, libunwind::Registers_ppc>::parseCFIs(
+                                                       oas, this->_machOSection->addr(), this->_machOSection->size(), 
+                                                       cfiArray, count, (void*)&parser, warnFunc);
+       if ( msg != NULL ) 
+               throwf("malformed __eh_frame section: %s", msg);
+}
+
+template <>
+void CFISection<ppc64>::cfiParse(class Parser<ppc64>& parser, uint8_t* buffer, 
+                                                                       libunwind::CFI_Atom_Info<CFISection<ppc64>::OAS>::CFI_Atom_Info cfiArray[], 
+                                                                       uint32_t count)
+{
+       // libunwind does not support ppc64
+       assert(count == 0);
+}
+
+template <>
+void CFISection<arm>::cfiParse(class Parser<arm>& parser, uint8_t* buffer, 
+                                                                       libunwind::CFI_Atom_Info<CFISection<arm>::OAS>::CFI_Atom_Info cfiArray[], 
+                                                                       uint32_t count)
+{
+       // arm does not use zero cost exceptions
+       assert(count == 0);
+}
+
+
+
+template <typename A>
+uint32_t CFISection<A>::computeAtomCount(class Parser<A>& parser, 
+                                                                                       struct Parser<A>::LabelAndCFIBreakIterator& it, 
+                                                                                       const struct Parser<A>::CFIInfoArray& cfis)
+{
+       return cfis.count;
+}
+
+
+
+template <typename A>
+uint32_t CFISection<A>::appendAtoms(class Parser<A>& parser, uint8_t* p, 
+                                                                       struct Parser<A>::LabelAndCFIBreakIterator& it, 
+                                                                       const struct Parser<A>::CFIInfoArray& cfis)
+{
+       this->_beginAtoms = (Atom<A>*)p;
+       // walk CFI_Atom_Info array and create atom for each entry
+       const CFI_Atom_Info* start = &cfis.array[0];
+       const CFI_Atom_Info* end   = &cfis.array[cfis.count];
+       for(const CFI_Atom_Info* a=start; a < end; ++a) {
+               Atom<A>* space = (Atom<A>*)p;
+               new (space) Atom<A>(*this, (a->isCIE ? "CIE" : "FDE"), a->address, a->size, 
+                                                                               ld::Atom::definitionRegular, ld::Atom::combineNever, ld::Atom::scopeTranslationUnit,
+                                                                               ld::Atom::typeCFI, ld::Atom::symbolTableNotInFinalLinkedImages, 
+                                                                               false, false, false, ld::Atom::Alignment(0));
+               p += sizeof(Atom<A>);
+       }
+       this->_endAtoms = (Atom<A>*)p;
+       return cfis.count;
+}
+
+
+template <> bool CFISection<x86_64>::bigEndian() { return false; }
+template <> bool CFISection<x86>::bigEndian() { return false; }
+template <> bool CFISection<arm>::bigEndian() { return false; }
+template <> bool CFISection<ppc>::bigEndian() { return true; }
+template <> bool CFISection<ppc64>::bigEndian() { return true; }
+
+
+template <>
+void CFISection<x86_64>::addCiePersonalityFixups(class Parser<x86_64>& parser, const CFI_Atom_Info* cieInfo)
+{
+       uint8_t personalityEncoding = cieInfo->u.cieInfo.personality.encodingOfTargetAddress;
+       if ( personalityEncoding == 0x9B ) {
+               // compiler always produces X86_64_RELOC_GOT with addend of 4 to personality function
+               // CFISection<x86_64>::cfiParse() set targetAddress to be symbolIndex + 4 + addressInCIE
+               uint32_t symbolIndex = cieInfo->u.cieInfo.personality.targetAddress - 4 
+                                                                       - cieInfo->address - cieInfo->u.cieInfo.personality.offsetInCFI;
+               const macho_nlist<P>& sym = parser.symbolFromIndex(symbolIndex);
+               const char* personalityName = parser.nameFromSymbol(sym);
+
+               Atom<x86_64>* cieAtom = this->findAtomByAddress(cieInfo->address);
+               Parser<x86_64>::SourceLocation src(cieAtom, cieInfo->u.cieInfo.personality.offsetInCFI);
+               parser.addFixup(src, ld::Fixup::k1of3, ld::Fixup::kindSetTargetAddress, false, personalityName);
+               parser.addFixup(src, ld::Fixup::k2of3, ld::Fixup::kindAddAddend, 4);
+               parser.addFixup(src, ld::Fixup::k3of3, ld::Fixup::kindStoreX86PCRel32GOT);
+       }
+       else if ( personalityEncoding != 0 ) {
+               throwf("unsupported address encoding (%02X) of personality function in CIE", 
+                               personalityEncoding);
+       }
+}
+
+template <>
+void CFISection<x86>::addCiePersonalityFixups(class Parser<x86>& parser, const CFI_Atom_Info* cieInfo)
+{
+       uint8_t personalityEncoding = cieInfo->u.cieInfo.personality.encodingOfTargetAddress;
+       if ( (personalityEncoding == 0x9B) || (personalityEncoding == 0x90) ) {
+               uint32_t offsetInCFI = cieInfo->u.cieInfo.personality.offsetInCFI;
+               uint32_t nlpAddr = cieInfo->u.cieInfo.personality.targetAddress;
+               Atom<x86>* cieAtom = this->findAtomByAddress(cieInfo->address);
+               Atom<x86>* nlpAtom = parser.findAtomByAddress(nlpAddr);
+               assert(nlpAtom->contentType() == ld::Atom::typeNonLazyPointer);
+               Parser<x86>::SourceLocation src(cieAtom, cieInfo->u.cieInfo.personality.offsetInCFI);
+
+               parser.addFixup(src, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, ld::Fixup::bindingByContentBound, nlpAtom);
+               parser.addFixup(src, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, cieAtom);
+               parser.addFixup(src, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, offsetInCFI);
+               parser.addFixup(src, ld::Fixup::k4of4, ld::Fixup::kindStoreLittleEndian32);
+       }
+       else if ( personalityEncoding != 0 ) {
+               throwf("unsupported address encoding (%02X) of personality function in CIE", personalityEncoding);
+       }
+}
+
+
+template <>
+void CFISection<ppc>::addCiePersonalityFixups(class Parser<ppc>& parser, const CFI_Atom_Info* cieInfo)
+{
+       uint8_t personalityEncoding = cieInfo->u.cieInfo.personality.encodingOfTargetAddress;
+       if ( (personalityEncoding == 0x9B) || (personalityEncoding == 0x90) ) {
+               uint32_t offsetInCFI = cieInfo->u.cieInfo.personality.offsetInCFI;
+               uint32_t nlpAddr = cieInfo->u.cieInfo.personality.targetAddress;
+               Atom<ppc>* cieAtom = this->findAtomByAddress(cieInfo->address);
+               Atom<ppc>* nlpAtom = parser.findAtomByAddress(nlpAddr);
+               assert(nlpAtom->contentType() == ld::Atom::typeNonLazyPointer);
+               Parser<ppc>::SourceLocation src(cieAtom, cieInfo->u.cieInfo.personality.offsetInCFI);
+
+               parser.addFixup(src, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, ld::Fixup::bindingByContentBound, nlpAtom);
+               parser.addFixup(src, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, cieAtom);
+               parser.addFixup(src, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, offsetInCFI);
+               parser.addFixup(src, ld::Fixup::k4of4, ld::Fixup::kindStoreBigEndian32);
+       }
+       else if ( personalityEncoding != 0 ) {
+               throwf("unsupported address encoding (%02X) of personality function in CIE", 
+                                       personalityEncoding);
+       }
+}
+
+
+template <typename A>
+void CFISection<A>::addCiePersonalityFixups(class Parser<A>& parser, const CFI_Atom_Info* cieInfo)
+{
+       // FIX ME
+       assert(0);
+}
+
+template <typename A>
+void CFISection<A>::makeFixups(class Parser<A>& parser, const struct Parser<A>::CFIInfoArray& cfis)
+{
+       ld::Fixup::Kind store32 = bigEndian() ? ld::Fixup::kindStoreBigEndian32 : ld::Fixup::kindStoreLittleEndian32;
+       ld::Fixup::Kind store64 = bigEndian() ? ld::Fixup::kindStoreBigEndian64 : ld::Fixup::kindStoreLittleEndian64;
+
+       // add all references for FDEs, including implicit group references
+       const CFI_Atom_Info* end = &cfis.array[cfis.count];
+       for(const CFI_Atom_Info* p = &cfis.array[0]; p < end; ++p) {
+               if ( p->isCIE ) {
+                       // add reference to personality function if used
+                       if ( p->u.cieInfo.personality.targetAddress != CFI_INVALID_ADDRESS ) {
+                               this->addCiePersonalityFixups(parser, p);
+                       }
+               }
+               else {
+                       // find FDE Atom
+                       Atom<A>* fdeAtom = this->findAtomByAddress(p->address);
+                       // find function Atom
+                       Atom<A>* functionAtom = parser.findAtomByAddress(p->u.fdeInfo.function.targetAddress);
+                       // find CIE Atom
+                       Atom<A>* cieAtom = this->findAtomByAddress(p->u.fdeInfo.cie.targetAddress);
+                       // find LSDA Atom
+                       Atom<A>* lsdaAtom = NULL;
+                       if ( p->u.fdeInfo.lsda.targetAddress != CFI_INVALID_ADDRESS ) {
+                               lsdaAtom = parser.findAtomByAddress(p->u.fdeInfo.lsda.targetAddress);
+                       }
+                       // add reference from FDE to CIE (always 32-bit pc-rel)
+                       typename Parser<A>::SourceLocation fdeToCieSrc(fdeAtom, p->u.fdeInfo.cie.offsetInCFI);
+                       parser.addFixup(fdeToCieSrc, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, fdeAtom);
+                       parser.addFixup(fdeToCieSrc, ld::Fixup::k2of4, ld::Fixup::kindAddAddend, p->u.fdeInfo.cie.offsetInCFI);
+                       parser.addFixup(fdeToCieSrc, ld::Fixup::k3of4, ld::Fixup::kindSubtractTargetAddress, cieAtom);
+                       parser.addFixup(fdeToCieSrc, ld::Fixup::k4of4, store32, cieAtom);
+
+                       // add reference from FDE to function
+                       typename Parser<A>::SourceLocation fdeToFuncSrc(fdeAtom, p->u.fdeInfo.function.offsetInCFI);
+                       switch (p->u.fdeInfo.function.encodingOfTargetAddress) {
+                               case DW_EH_PE_pcrel|DW_EH_PE_ptr:
+                                       if ( sizeof(typename A::P::uint_t) == 8 ) {
+                                               parser.addFixup(fdeToFuncSrc, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, functionAtom);
+                                               parser.addFixup(fdeToFuncSrc, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, fdeAtom);
+                                               parser.addFixup(fdeToFuncSrc, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, p->u.fdeInfo.function.offsetInCFI);
+                                               parser.addFixup(fdeToFuncSrc, ld::Fixup::k4of4, store64);
+                                               break;
+                                       }
+                                       // else fall into 32-bit case
+                               case DW_EH_PE_pcrel|DW_EH_PE_sdata4:
+                                       parser.addFixup(fdeToFuncSrc, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, functionAtom);
+                                       parser.addFixup(fdeToFuncSrc, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, fdeAtom);
+                                       parser.addFixup(fdeToFuncSrc, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, p->u.fdeInfo.function.offsetInCFI);
+                                       parser.addFixup(fdeToFuncSrc, ld::Fixup::k4of4, store32);
+                                       break;
+                               default:
+                                       throw "unsupported encoding in FDE of pointer to function";
+                       }
+               
+                       // add reference from FDE to LSDA
+                       typename Parser<A>::SourceLocation fdeToLsdaSrc(fdeAtom,  p->u.fdeInfo.lsda.offsetInCFI);
+                       if ( lsdaAtom != NULL ) {
+                               switch (p->u.fdeInfo.lsda.encodingOfTargetAddress) {
+                                       case DW_EH_PE_pcrel|DW_EH_PE_ptr:
+                                               if ( sizeof(typename A::P::uint_t) == 8 ) {
+                                                       parser.addFixup(fdeToLsdaSrc, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, lsdaAtom);
+                                                       parser.addFixup(fdeToLsdaSrc, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, fdeAtom);
+                                                       parser.addFixup(fdeToLsdaSrc, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, p->u.fdeInfo.lsda.offsetInCFI);
+                                                       parser.addFixup(fdeToLsdaSrc, ld::Fixup::k4of4, store64);
+                                                       break;
+                                               }
+                                               // else fall into 32-bit case
+                                       case DW_EH_PE_pcrel|DW_EH_PE_sdata4:
+                                               parser.addFixup(fdeToLsdaSrc, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, lsdaAtom);
+                                               parser.addFixup(fdeToLsdaSrc, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, fdeAtom);
+                                               parser.addFixup(fdeToLsdaSrc, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, p->u.fdeInfo.lsda.offsetInCFI);
+                                               parser.addFixup(fdeToLsdaSrc, ld::Fixup::k4of4, store32);
+                                       break;
+                                       default:
+                                               throw "unsupported encoding in FDE of pointer to LSDA";
+                               }
+                       }
+                       
+                       // FDE is in group lead by function atom
+                       typename Parser<A>::SourceLocation fdeSrc(functionAtom,0);
+                       parser.addFixup(fdeSrc, ld::Fixup::k1of1, ld::Fixup::kindNoneGroupSubordinateFDE, fdeAtom);
+                       
+                       // LSDA is in group lead by function atom
+                       if ( lsdaAtom != NULL ) {
+                               parser.addFixup(fdeSrc, ld::Fixup::k1of1, ld::Fixup::kindNoneGroupSubordinateLSDA, lsdaAtom);
+                       }
+               }
+       }
+}
+
+
+
+
+template <typename A>
+const void*     CFISection<A>::OAS::mappedAddress(pint_t addr)
+{
+       if ( (_ehFrameStartAddr <= addr) && (addr < _ehFrameEndAddr) )
+               return &_ehFrameContent[addr-_ehFrameStartAddr];
+       else {
+               // requested bytes are not in __eh_frame section
+               // this can occur when examining the instruction bytes in the __text
+               File<A>& file = _ehFrameSection.file();
+               for (uint32_t i=0; i < file._sectionsArrayCount; ++i ) {
+                       const macho_section<typename A::P>* sect = file._sectionsArray[i]->machoSection();
+                       // TentativeDefinitionSection and AbsoluteSymbolSection have no mach-o section
+                       if ( sect != NULL ) {
+                               if ( (sect->addr() <= addr) && (addr < (sect->addr()+sect->size())) ) {
+                                       return file.fileContent() + sect->offset() + addr - sect->addr();
+                               }
+                       }
+               }
+               throwf("__eh_frame parsing problem.  Can't find target of reference to address 0x%08llX", (uint64_t)addr);
+       }
+}
+               
+
+template <typename A>
+uint64_t CFISection<A>::OAS::getULEB128(pint_t& logicalAddr, pint_t end)
+{
+       uintptr_t size = (end - logicalAddr);
+       libunwind::LocalAddressSpace::pint_t laddr = (libunwind::LocalAddressSpace::pint_t)mappedAddress(logicalAddr);
+       libunwind::LocalAddressSpace::pint_t sladdr = laddr;
+       uint64_t result = libunwind::LocalAddressSpace::getULEB128(laddr, laddr+size);
+       logicalAddr += (laddr-sladdr);
+       return result;
+}
+
+template <typename A>
+int64_t CFISection<A>::OAS::getSLEB128(pint_t& logicalAddr, pint_t end)
+{
+       uintptr_t size = (end - logicalAddr);
+       libunwind::LocalAddressSpace::pint_t laddr = (libunwind::LocalAddressSpace::pint_t)mappedAddress(logicalAddr);
+       libunwind::LocalAddressSpace::pint_t sladdr = laddr;
+       int64_t result = libunwind::LocalAddressSpace::getSLEB128(laddr, laddr+size);
+       logicalAddr += (laddr-sladdr);
+       return result;
+}
+
+template <typename A>
+typename A::P::uint_t CFISection<A>::OAS::getEncodedP(pint_t& addr, pint_t end, uint8_t encoding)
+{
+       pint_t startAddr = addr;
+       pint_t p = addr;
+       pint_t result;
+
+       // first get value
+       switch (encoding & 0x0F) {
+               case DW_EH_PE_ptr:
+                       result = getP(addr);
+                       p += sizeof(pint_t);
+                       addr = (pint_t)p;
+                       break;
+               case DW_EH_PE_uleb128:
+                       result = getULEB128(addr, end);
+                       break;
+               case DW_EH_PE_udata2:
+                       result = get16(addr);
+                       p += 2;
+                       addr = (pint_t)p;
+                       break;
+               case DW_EH_PE_udata4:
+                       result = get32(addr);
+                       p += 4;
+                       addr = (pint_t)p;
+                       break;
+               case DW_EH_PE_udata8:
+                       result = get64(addr);
+                       p += 8;
+                       addr = (pint_t)p;
+                       break;
+               case DW_EH_PE_sleb128:
+                       result = getSLEB128(addr, end);
+                       break;
+               case DW_EH_PE_sdata2:
+                       result = (int16_t)get16(addr);
+                       p += 2;
+                       addr = (pint_t)p;
+                       break;
+               case DW_EH_PE_sdata4:
+                       result = (int32_t)get32(addr);
+                       p += 4;
+                       addr = (pint_t)p;
+                       break;
+               case DW_EH_PE_sdata8:
+                       result = get64(addr);
+                       p += 8;
+                       addr = (pint_t)p;
+                       break;
+               default:
+                       throwf("ObjectFileAddressSpace<A>::getEncodedP() encoding 0x%08X not supported", encoding);
+       }
+       
+       // then add relative offset
+       switch ( encoding & 0x70 ) {
+               case DW_EH_PE_absptr:
+                       // do nothing
+                       break;
+               case DW_EH_PE_pcrel:
+                       result += startAddr;
+                       break;
+               case DW_EH_PE_textrel:
+                       throw "DW_EH_PE_textrel pointer encoding not supported";
+                       break;
+               case DW_EH_PE_datarel:
+                       throw "DW_EH_PE_datarel pointer encoding not supported";
+                       break;
+               case DW_EH_PE_funcrel:
+                       throw "DW_EH_PE_funcrel pointer encoding not supported";
+                       break;
+               case DW_EH_PE_aligned:
+                       throw "DW_EH_PE_aligned pointer encoding not supported";
+                       break;
+               default:
+                       throwf("ObjectFileAddressSpace<A>::getEncodedP() encoding 0x%08X not supported", encoding);
+                       break;
+       }
+
+//  Note: DW_EH_PE_indirect is only used in CIEs to refernce the personality pointer
+//  When parsing .o files that pointer contains zero, so we don't to return that.
+//  Instead we skip the dereference and return the address of the pointer.
+//     if ( encoding & DW_EH_PE_indirect )
+//             result = getP(result);
+       
+       return result;
+}
+
+template <typename A>
+SymboledSection<A>::SymboledSection(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
+       : Section<A>(f, s), _type(ld::Atom::typeUnclassified) 
+{
+       switch ( s->flags() & SECTION_TYPE ) {
+               case S_ZEROFILL:
+                       _type = ld::Atom::typeZeroFill;
+                       break;
+               case S_MOD_INIT_FUNC_POINTERS:
+                       _type = ld::Atom::typeInitializerPointers;
+                       break;
+               case S_MOD_TERM_FUNC_POINTERS:
+                       _type = ld::Atom::typeTerminatorPointers;
+                       break;
+               case S_THREAD_LOCAL_VARIABLES:
+                       _type = ld::Atom::typeTLV;
+                       break;
+               case S_THREAD_LOCAL_ZEROFILL:
+                       _type = ld::Atom::typeTLVZeroFill;
+                       break;
+               case S_THREAD_LOCAL_REGULAR:
+                       _type = ld::Atom::typeTLVInitialValue;
+                       break;
+               case S_THREAD_LOCAL_INIT_FUNCTION_POINTERS:
+                       _type = ld::Atom::typeTLVInitializerPointers;
+                       break;
+               case S_REGULAR:
+                       if ( strncmp(s->sectname(), "__gcc_except_tab", 16) == 0 )
+                               _type = ld::Atom::typeLSDA;
+                       break;
+       }
+}
+
+
+template <typename A>
+bool SymboledSection<A>::dontDeadStrip() 
+{
+       switch ( _type ) {
+               case ld::Atom::typeInitializerPointers:
+               case ld::Atom::typeTerminatorPointers:
+                       return true;
+               default:
+                       // model an object file without MH_SUBSECTIONS_VIA_SYMBOLS as one in which nothing can be dead stripped
+                       if ( ! this->_file.canScatterAtoms() )
+                               return true;
+                       // call inherited
+                       return Section<A>::dontDeadStrip();
+       }
+       return false;
+}
+
+
+template <typename A>
+uint32_t SymboledSection<A>::computeAtomCount(class Parser<A>& parser, 
+                                                                                               struct Parser<A>::LabelAndCFIBreakIterator& it, 
+                                                                                               const struct Parser<A>::CFIInfoArray&)
+{
+       const pint_t startAddr = this->_machOSection->addr();
+       const pint_t endAddr = startAddr + this->_machOSection->size();
+       const uint32_t sectNum = this->sectionNum(parser);
+
+       uint32_t count = 0;
+       pint_t  addr;
+       pint_t  size;
+       const macho_nlist<P>* sym;
+       while ( it.next(parser, sectNum, startAddr, endAddr, &addr, &size, &sym) ) {
+               ++count;
+       }
+       //fprintf(stderr, "computeAtomCount(%s,%s) => %d\n", this->segmentName(), this->sectionName(), count);
+       return count;
+}
+
+template <typename A>
+uint32_t SymboledSection<A>::appendAtoms(class Parser<A>& parser, uint8_t* p, 
+                                                                                       struct Parser<A>::LabelAndCFIBreakIterator& it, 
+                                                                                       const struct Parser<A>::CFIInfoArray&)
+{
+       this->_beginAtoms = (Atom<A>*)p;
+
+       //fprintf(stderr, "SymboledSection::appendAtoms() in section %s\n", this->_machOSection->sectname());
+       const pint_t startAddr = this->_machOSection->addr();
+       const pint_t endAddr = startAddr + this->_machOSection->size();
+       const uint32_t sectNum = this->sectionNum(parser);
+
+       uint32_t count = 0;
+       pint_t  addr;
+       pint_t  size;
+       const macho_nlist<P>* label;
+       while ( it.next(parser, sectNum, startAddr, endAddr, &addr, &size, &label) ) {
+               Atom<A>* allocatedSpace = (Atom<A>*)p;
+               // is break because of label or CFI?
+               if ( label != NULL ) {
+                       // The size is computed based on the address of the next label (or the end of the section for the last label)
+                       // If there are two labels at the same address, we want them one to be an alias of the other.
+                       // If the label is at the end of a section, it is has zero size, but is not an alias
+                       const bool isAlias = ( (size == 0) && (addr <  endAddr) );
+                       new (allocatedSpace) Atom<A>(*this, parser, *label, size, isAlias);
+                       if ( isAlias )
+                               this->_hasAliases = true;
+               }
+               else {
+                       new (allocatedSpace) Atom<A>(*this, "anon", addr, size, ld::Atom::definitionRegular, ld::Atom::combineNever, 
+                                                                               ld::Atom::scopeTranslationUnit, this->contentType(), ld::Atom::symbolTableNotIn, 
+                                                                               this->dontDeadStrip(), false, false, this->alignmentForAddress(addr));
+               }
+               p += sizeof(Atom<A>);
+               ++count;
+       }
+
+       this->_endAtoms = (Atom<A>*)p;
+       return count;
+}
+
+
+template <typename A>
+uint32_t ImplicitSizeSection<A>::computeAtomCount(class Parser<A>& parser, 
+                                                                                                       struct Parser<A>::LabelAndCFIBreakIterator& it, 
+                                                                                                       const struct Parser<A>::CFIInfoArray&)
+{
+       uint32_t count = 0;
+       const macho_section<P>* sect = this->machoSection();
+       const pint_t startAddr = sect->addr();
+       const pint_t endAddr = startAddr + sect->size();
+       for (pint_t addr = startAddr; addr < endAddr; addr += elementSizeAtAddress(addr) ) {
+               if ( useElementAt(parser, it, addr) ) 
+                       ++count;
+       }
+       if ( it.fileHasOverlappingSymbols && (sect->size() != 0) && (this->combine(parser, startAddr) == ld::Atom::combineByNameAndContent) ) {
+               // if there are multiple labels in this section for the same address, then clone them into multi atoms
+               pint_t  prevSymbolAddr = (pint_t)(-1);
+               uint8_t prevSymbolSectNum = 0;
+               for(uint32_t i=0; i < it.sortedSymbolCount; ++i) {
+                       const macho_nlist<P>& sym = parser.symbolFromIndex(it.sortedSymbolIndexes[i]);
+                       const pint_t symbolAddr = sym.n_value();
+                       const pint_t symbolSectNum = sym.n_sect();
+                       if ( (symbolAddr == prevSymbolAddr) && (prevSymbolSectNum == symbolSectNum) && (symbolSectNum == this->sectionNum(parser)) ) { 
+                               ++count;
+                       }
+                       prevSymbolAddr = symbolAddr;
+                       prevSymbolSectNum = symbolSectNum;
+               }
+       }
+       return count;
+}
+
+template <typename A>
+uint32_t ImplicitSizeSection<A>::appendAtoms(class Parser<A>& parser, uint8_t* p, 
+                                                                                       struct Parser<A>::LabelAndCFIBreakIterator& it, 
+                                                                                       const struct Parser<A>::CFIInfoArray&)
+{
+       this->_beginAtoms = (Atom<A>*)p;
+       
+       const macho_section<P>* sect = this->machoSection();
+       const pint_t startAddr = sect->addr();
+       const pint_t endAddr = startAddr + sect->size();
+       const uint32_t sectNum = this->sectionNum(parser);
+       //fprintf(stderr, "ImplicitSizeSection::appendAtoms() in section %s\n", sect->sectname());
+       uint32_t count = 0;
+       pint_t  foundAddr;
+       pint_t  size;
+       const macho_nlist<P>* foundLabel;
+       Atom<A>* allocatedSpace;
+       while ( it.next(parser, sectNum, startAddr, endAddr, &foundAddr, &size, &foundLabel) ) {
+               if ( foundLabel != NULL ) {
+                       pint_t labeledAtomSize = this->elementSizeAtAddress(foundAddr);
+                       allocatedSpace = (Atom<A>*)p;
+                       if ( this->ignoreLabel(parser.nameFromSymbol(*foundLabel)) ) {
+                               //fprintf(stderr, "  0x%08llX make annon\n", (uint64_t)foundAddr);
+                               new (allocatedSpace) Atom<A>(*this, this->unlabeledAtomName(parser, foundAddr), foundAddr, 
+                                                                                       this->elementSizeAtAddress(foundAddr), this->definition(), 
+                                                                                       this->combine(parser, foundAddr), this->scopeAtAddress(parser, foundAddr), 
+                                                                                       this->contentType(), this->symbolTableInclusion(), 
+                                                                                       this->dontDeadStrip(), false, false, this->alignmentForAddress(foundAddr));
+                       }
+                       else {
+                               // make named atom for label
+                               //fprintf(stderr, "  0x%08llX make labeled\n", (uint64_t)foundAddr);
+                               new (allocatedSpace) Atom<A>(*this, parser, *foundLabel, labeledAtomSize);
+                       }
+                       ++count;
+                       p += sizeof(Atom<A>);
+                       foundAddr += labeledAtomSize;
+                       size -= labeledAtomSize;
+               }
+               // some number of anonymous atoms
+               for (pint_t addr = foundAddr; addr < (foundAddr+size); addr += elementSizeAtAddress(addr) ) {
+                       // make anon atoms for area before label
+                       if ( this->useElementAt(parser, it, addr) ) {
+                               //fprintf(stderr, "  0x%08llX make annon\n", (uint64_t)addr);
+                               allocatedSpace = (Atom<A>*)p;
+                               new (allocatedSpace) Atom<A>(*this, this->unlabeledAtomName(parser, addr), addr, this->elementSizeAtAddress(addr), 
+                                                                                       this->definition(), this->combine(parser, addr), this->scopeAtAddress(parser, addr), 
+                                                                                       this->contentType(), this->symbolTableInclusion(), 
+                                                                                       this->dontDeadStrip(), false, false, this->alignmentForAddress(addr));
+                               ++count;
+                               p += sizeof(Atom<A>);
+                       }
+               }
+       }
+
+       this->_endAtoms = (Atom<A>*)p;
+
+       return count;
+}
+
+
+template <typename A>
+unsigned long Literal4Section<A>::contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const
+{
+       const uint32_t* literalContent = (uint32_t*)atom->contentPointer();
+       return *literalContent;
+}
+
+template <typename A>
+bool Literal4Section<A>::canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs, 
+                                                                                                       const ld::IndirectBindingTable& ind) const
+{
+       assert(this->type() == rhs.section().type());
+       const uint32_t* literalContent = (uint32_t*)atom->contentPointer();
+       
+       const Atom<A>* rhsAtom = dynamic_cast<const Atom<A>*>(&rhs);
+       assert(rhsAtom != NULL);
+       if ( rhsAtom != NULL ) {
+               const uint32_t* rhsLiteralContent = (uint32_t*)rhsAtom->contentPointer();
+               return (*literalContent == *rhsLiteralContent);
+       }
+       return false;
+}
+
+
+template <typename A>
+unsigned long Literal8Section<A>::contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const
+{
+#if __LP64__
+       const uint64_t* literalContent = (uint64_t*)atom->contentPointer();
+       return *literalContent;
+#else
+       unsigned long hash = 5381;
+       const uint8_t* byteContent = atom->contentPointer();
+       for (int i=0; i < 8; ++i) {
+               hash = hash * 33 + byteContent[i];
+       }
+       return hash;
+#endif
+}
+
+template <typename A>
+bool Literal8Section<A>::canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs, 
+                                                                                                       const ld::IndirectBindingTable& ind) const
+{
+       if ( rhs.section().type() != ld::Section::typeLiteral8 )
+               return false;
+       assert(this->type() == rhs.section().type());
+       const uint64_t* literalContent = (uint64_t*)atom->contentPointer();
+       
+       const Atom<A>* rhsAtom = dynamic_cast<const Atom<A>*>(&rhs);
+       assert(rhsAtom != NULL);
+       if ( rhsAtom != NULL ) {
+               const uint64_t* rhsLiteralContent = (uint64_t*)rhsAtom->contentPointer();
+               return (*literalContent == *rhsLiteralContent);
+       }
+       return false;
+}
+
+
+template <typename A>
+unsigned long Literal16Section<A>::contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const
+{
+       unsigned long hash = 5381;
+       const uint8_t* byteContent = atom->contentPointer();
+       for (int i=0; i < 16; ++i) {
+               hash = hash * 33 + byteContent[i];
+       }
+       return hash;
+}
+
+template <typename A>
+bool Literal16Section<A>::canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs, 
+                                                                                                       const ld::IndirectBindingTable& ind) const
+{
+       if ( rhs.section().type() != ld::Section::typeLiteral16 )
+               return false;
+       assert(this->type() == rhs.section().type());
+       const uint64_t* literalContent = (uint64_t*)atom->contentPointer();
+       
+       const Atom<A>* rhsAtom = dynamic_cast<const Atom<A>*>(&rhs);
+       assert(rhsAtom != NULL);
+       if ( rhsAtom != NULL ) {
+               const uint64_t* rhsLiteralContent = (uint64_t*)rhsAtom->contentPointer();
+               return ((literalContent[0] == rhsLiteralContent[0]) && (literalContent[1] == rhsLiteralContent[1]));
+       }
+       return false;
+}
+
+
+
+template <typename A>
+typename A::P::uint_t CStringSection<A>::elementSizeAtAddress(pint_t addr)
+{
+       const macho_section<P>* sect = this->machoSection();
+       const char* stringContent = (char*)(this->file().fileContent() + sect->offset() + addr - sect->addr());
+       return strlen(stringContent) + 1;
+}
+
+template <typename A>
+bool CStringSection<A>::useElementAt(Parser<A>& parser, struct Parser<A>::LabelAndCFIBreakIterator& it, pint_t addr)
+{
+       return true;
+}
+
+template <typename A>
+Atom<A>* CStringSection<A>::findAtomByAddress(pint_t addr)
+{
+       Atom<A>* result = this->findContentAtomByAddress(addr, this->_beginAtoms, this->_endAtoms);
+       return result;
+}
+
+template <typename A>
+unsigned long CStringSection<A>::contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const
+{
+       unsigned long hash = 5381;
+       const char* stringContent = (char*)atom->contentPointer();
+       for (const char* s = stringContent; *s != '\0'; ++s) {
+               hash = hash * 33 + *s;
+       }
+       return hash;
+}
+
+
+template <typename A>
+bool CStringSection<A>::canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs, 
+                                                                                                       const ld::IndirectBindingTable& ind) const
+{
+       if ( rhs.section().type() != ld::Section::typeCString )
+               return false;
+       assert(this->type() == rhs.section().type());
+       assert(strcmp(this->sectionName(), rhs.section().sectionName())== 0);
+       assert(strcmp(this->segmentName(), rhs.section().segmentName())== 0);
+       const char* stringContent = (char*)atom->contentPointer();
+       
+       const Atom<A>* rhsAtom = dynamic_cast<const Atom<A>*>(&rhs);
+       assert(rhsAtom != NULL);
+       if ( rhsAtom != NULL ) {
+               if ( atom->_size != rhsAtom->_size )
+                       return false;
+               const char* rhsStringContent = (char*)rhsAtom->contentPointer();
+               return (strcmp(stringContent, rhsStringContent) == 0);
+       }
+       return false;
+}
+
+
+template <>
+ld::Fixup::Kind NonLazyPointerSection<x86>::fixupKind()
+{
+       return ld::Fixup::kindStoreLittleEndian32;
+}
+
+template <>
+ld::Fixup::Kind NonLazyPointerSection<arm>::fixupKind()
+{
+       return ld::Fixup::kindStoreLittleEndian32;
+}
+
+template <>
+ld::Fixup::Kind NonLazyPointerSection<ppc>::fixupKind()
+{
+       return ld::Fixup::kindStoreBigEndian32;
+}
+
+template <>
+ld::Fixup::Kind NonLazyPointerSection<ppc64>::fixupKind()
+{
+       return ld::Fixup::kindStoreBigEndian64;
+}
+
+template <>
+void NonLazyPointerSection<x86_64>::makeFixups(class Parser<x86_64>& parser, const struct Parser<x86_64>::CFIInfoArray&)
+{
+       assert(0 && "x86_64 should not have non-lazy-pointer sections in .o files");
+}
+
+template <typename A>
+void NonLazyPointerSection<A>::makeFixups(class Parser<A>& parser, const struct Parser<A>::CFIInfoArray&)
+{
+       // add references for each NLP atom based on indirect symbol table
+       const macho_section<P>* sect = this->machoSection();
+       const pint_t endAddr = sect->addr() + sect->size();
+       for( pint_t addr = sect->addr(); addr < endAddr; addr += sizeof(pint_t)) {
+               typename Parser<A>::SourceLocation      src;
+               typename Parser<A>::TargetDesc          target;
+               src.atom = this->findAtomByAddress(addr);
+               src.offsetInAtom = 0;
+               uint32_t symIndex = parser.symbolIndexFromIndirectSectionAddress(addr, sect);
+               target.atom = NULL;
+               target.name = NULL;
+               target.weakImport = false;
+               target.addend = 0;
+               if ( symIndex == INDIRECT_SYMBOL_LOCAL ) {
+                       // use direct reference for local symbols
+                       const pint_t* nlpContent = (pint_t*)(this->file().fileContent() + sect->offset() + addr - sect->addr());
+                       pint_t targetAddr = P::getP(*nlpContent);
+                       target.atom = parser.findAtomByAddress(targetAddr);
+                       target.weakImport = false;
+                       target.addend = (targetAddr - target.atom->objectAddress());
+                       // <rdar://problem/8385011> if pointer to thumb function, mask of thumb bit (not an addend of +1)
+                       if ( target.atom->isThumb() )
+                               target.addend &= (-2); 
+                       assert(src.atom->combine() == ld::Atom::combineNever);
+               }
+               else {
+                       const macho_nlist<P>& sym = parser.symbolFromIndex(symIndex);
+                       // use direct reference for local symbols
+                       if ( ((sym.n_type() & N_TYPE) == N_SECT) && ((sym.n_type() & N_EXT) == 0) ) {
+                               parser.findTargetFromAddressAndSectionNum(sym.n_value(), sym.n_sect(), target);
+                               assert(src.atom->combine() == ld::Atom::combineNever);
+                       }
+                       else {
+                               target.name = parser.nameFromSymbol(sym);
+                               target.weakImport = parser.weakImportFromSymbol(sym);
+                               assert(src.atom->combine() == ld::Atom::combineByNameAndReferences);
+                       }
+               }
+               parser.addFixups(src, this->fixupKind(), target);
+       }
+}
+
+template <typename A>
+ld::Atom::Combine NonLazyPointerSection<A>::combine(Parser<A>& parser, pint_t addr)
+{
+       const macho_section<P>* sect = this->machoSection();
+       uint32_t symIndex = parser.symbolIndexFromIndirectSectionAddress(addr, sect);
+       if ( symIndex == INDIRECT_SYMBOL_LOCAL)
+               return ld::Atom::combineNever;
+               
+       // don't coalesce non-lazy-pointers to local symbols
+       const macho_nlist<P>& sym = parser.symbolFromIndex(symIndex);
+       if ( ((sym.n_type() & N_TYPE) == N_SECT) && ((sym.n_type() & N_EXT) == 0) ) 
+               return ld::Atom::combineNever;
+       
+       return ld::Atom::combineByNameAndReferences;
+}
+
+template <typename A>
+const char* NonLazyPointerSection<A>::targetName(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) 
+{
+       assert(atom->combine() == ld::Atom::combineByNameAndReferences);
+       assert(atom->fixupCount() == 1);
+       ld::Fixup::iterator fit = atom->fixupsBegin();
+       const char* name = NULL;
+       switch ( fit->binding ) {
+               case ld::Fixup::bindingByNameUnbound:
+                       name = fit->u.name;
+                       break;
+               case ld::Fixup::bindingByContentBound:
+                       name = fit->u.target->name();
+                       break;
+               case ld::Fixup::bindingsIndirectlyBound:
+                       name = ind.indirectName(fit->u.bindingIndex);
+                       break;
+               default:
+                       assert(0);
+       }
+       assert(name != NULL);
+       return name;
+}
+
+template <typename A>
+unsigned long NonLazyPointerSection<A>::contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const
+{
+       assert(atom->combine() == ld::Atom::combineByNameAndReferences);
+       unsigned long hash = 9508;
+       for (const char* s = this->targetName(atom, ind); *s != '\0'; ++s) {
+               hash = hash * 33 + *s;
+       }
+       return hash;
+}
+
+template <typename A>
+bool NonLazyPointerSection<A>::canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs, 
+                                                                                                       const ld::IndirectBindingTable& indirectBindingTable) const
+{
+       if ( rhs.section().type() != ld::Section::typeNonLazyPointer )
+               return false;
+       assert(this->type() == rhs.section().type());
+       // there can be many non-lazy pointer in different section names
+       // we only want to coalesce in same section name
+       if ( *this != rhs.section() )
+               return false;
+       const Atom<A>* rhsAtom = dynamic_cast<const Atom<A>*>(&rhs);
+       assert(rhsAtom !=  NULL);
+       const char* thisName = this->targetName(atom, indirectBindingTable);
+       const char* rhsName = this->targetName(rhsAtom, indirectBindingTable);
+       return (strcmp(thisName, rhsName) == 0);
+}
+
+template <typename A>
+ld::Atom::Scope NonLazyPointerSection<A>::scopeAtAddress(Parser<A>& parser, pint_t addr)
+{ 
+       const macho_section<P>* sect = this->machoSection();
+       uint32_t symIndex = parser.symbolIndexFromIndirectSectionAddress(addr, sect);
+       if ( symIndex == INDIRECT_SYMBOL_LOCAL)
+               return ld::Atom::scopeTranslationUnit;
+       else
+               return ld::Atom::scopeLinkageUnit; 
+}
+
+
+template <typename A>
+const uint8_t* CFStringSection<A>::targetContent(const class Atom<A>* atom, const ld::IndirectBindingTable& ind,
+                                                                                                       ContentType* ct, unsigned int* count)
+{
+       *ct = contentUnknown;
+       for (ld::Fixup::iterator fit=atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+               const ld::Atom* targetAtom = NULL;
+               switch ( fit->binding ) {
+                       case ld::Fixup::bindingByNameUnbound:
+                               // ignore reference to ___CFConstantStringClassReference
+                               // we are just looking for reference to backing string data
+                               assert(fit->offsetInAtom == 0);
+                               assert(strcmp(fit->u.name, "___CFConstantStringClassReference") == 0);
+                               break;
+                       case ld::Fixup::bindingDirectlyBound:
+                       case ld::Fixup::bindingByContentBound:
+                               targetAtom = fit->u.target;
+                               break;
+                       case ld::Fixup::bindingsIndirectlyBound:
+                               targetAtom = ind.indirectAtom(fit->u.bindingIndex);
+                               break;
+                       default:
+                               assert(0 && "bad binding type");
+               }
+               assert(targetAtom != NULL);
+               const Atom<A>* target = dynamic_cast<const Atom<A>*>(targetAtom);
+               if ( targetAtom->section().type() == ld::Section::typeCString ) {
+                       *ct = contentUTF8;
+                       *count = targetAtom->size();
+               }
+               else if ( targetAtom->section().type() == ld::Section::typeUTF16Strings ) {
+                       *ct = contentUTF16;
+                       *count = (targetAtom->size()+1)/2; // round up incase of buggy compiler that has only one trailing zero byte
+               }
+               assert(target !=  NULL);
+               return target->contentPointer();
+       }
+       assert(0);
+       return NULL;
+}
+
+template <typename A>
+unsigned long CFStringSection<A>::contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const
+{
+       // base hash of CFString on hash of cstring it wraps
+       ContentType cType;
+       unsigned long hash;
+       unsigned int charCount;
+       const uint8_t* content = this->targetContent(atom, ind, &cType, &charCount);
+       switch ( cType ) {
+               case contentUTF8:
+                       hash = 9408;
+                       for (const char* s = (char*)content; *s != '\0'; ++s) {
+                               hash = hash * 33 + *s;
+                       }
+                       return hash;
+               case contentUTF16:
+                       hash = 407955;
+                       --charCount; // don't add last 0x0000 to hash because some buggy compilers only have trailing single byte
+                       for (const uint16_t* s = (uint16_t*)content; charCount > 0; ++s, --charCount) {
+                               hash = hash * 1025 + *s;
+                       }
+                       return hash;
+               case contentUnknown:
+                       return 0;
+       }
+       return 0;
+}
+
+
+template <typename A>
+bool CFStringSection<A>::canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs, 
+                                                                                                       const ld::IndirectBindingTable& indirectBindingTable) const
+{
+       if ( atom == &rhs )
+               return true;
+       if ( rhs.section().type() != ld::Section::typeCFString)
+               return false;
+       assert(this->type() == rhs.section().type());
+       assert(strcmp(this->sectionName(), "__cfstring") == 0);
+       
+       ContentType thisType;
+       unsigned int charCount;
+       const uint8_t* cstringContent = this->targetContent(atom, indirectBindingTable, &thisType, &charCount);
+       ContentType rhsType;
+       const Atom<A>* rhsAtom = dynamic_cast<const Atom<A>*>(&rhs);
+       assert(rhsAtom !=  NULL);
+       unsigned int rhsCharCount;
+       const uint8_t* rhsStringContent = this->targetContent(rhsAtom, indirectBindingTable, &rhsType, &rhsCharCount);
+
+       if ( thisType != rhsType )
+               return false;
+
+       // no need to compare content of pointers are already the same
+       if ( cstringContent == rhsStringContent ) 
+               return true;
+       
+       // no need to compare content if size is different
+       if ( charCount != rhsCharCount )
+               return false;
+
+       switch ( thisType ) {
+               case contentUTF8:
+                       return (strcmp((char*)cstringContent, (char*)rhsStringContent) == 0);
+               case contentUTF16:
+                       {
+                               const uint16_t* cstringContent16 = (uint16_t*)cstringContent;
+                               const uint16_t* rhsStringContent16 = (uint16_t*)rhsStringContent;
+                               for (unsigned int i = 0; i < charCount; ++i) {
+                                       if ( cstringContent16[i] != rhsStringContent16[i] )
+                                               return false;
+                               }
+                               return true;
+                       }
+               case contentUnknown:
+                       return false;
+       }
+       return false;
+}
+
+
+template <typename A>
+typename A::P::uint_t ObjC1ClassSection<A>::elementSizeAtAddress(pint_t addr)
+{
+       // nominal size for each class is 48 bytes, but sometimes the compiler
+       // over aligns and there is padding after class data
+       const macho_section<P>* sct = this->machoSection();
+       uint32_t align = 1 << sct->align();
+       uint32_t size = ((12 * sizeof(pint_t)) + align-1) & (-align);
+       return size;
+}
+
+template <typename A>
+const char* ObjC1ClassSection<A>::unlabeledAtomName(Parser<A>& parser, pint_t addr)
+{
+       // 8-bytes into class object is pointer to class name
+       const macho_section<P>* sct = this->machoSection();
+       uint32_t classObjcFileOffset = sct->offset() - sct->addr() + addr;
+       const uint8_t* mappedFileContent = this->file().fileContent();
+       pint_t nameAddr = P::getP(*((pint_t*)(mappedFileContent+classObjcFileOffset+2*sizeof(pint_t))));
+       
+       // find section containing string address to get string bytes
+       const macho_section<P>* const sections = parser.firstMachOSection();
+       const uint32_t sectionCount = parser.machOSectionCount();
+       for (uint32_t i=0; i < sectionCount; ++i) {
+               const macho_section<P>* aSect = &sections[i];
+               if ( (aSect->addr() <= nameAddr) && (nameAddr < (aSect->addr()+aSect->size())) ) {
+                       assert((aSect->flags() & SECTION_TYPE) == S_CSTRING_LITERALS);
+                       uint32_t nameFileOffset = aSect->offset() - aSect->addr() + nameAddr;
+                       const char* name = (char*)mappedFileContent + nameFileOffset;
+                       // spin through symbol table to find absolute symbol corresponding to this class
+                       for (uint32_t s=0; s < parser.symbolCount(); ++s) {
+                               const macho_nlist<P>& sym =     parser.symbolFromIndex(s);
+                               if ( (sym.n_type() & N_TYPE) != N_ABS )
+                                       continue;
+                               const char* absName = parser.nameFromSymbol(sym);
+                               if ( strncmp(absName, ".objc_class_name_", 17) == 0 ) {
+                                       if ( strcmp(&absName[17], name) == 0 )
+                                               return absName;
+                               }
+                       }
+                       assert(0 && "obj class name not found in symbol table");
+               }
+       }
+       assert(0 && "obj class name not found");
+       return "unknown objc class";
+}
+
+
+template <typename A>
+const char* ObjC2ClassRefsSection<A>::targetClassName(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const
+{
+       assert(atom->fixupCount() == 1);
+       ld::Fixup::iterator fit = atom->fixupsBegin();
+       const char* className = NULL;
+       switch ( fit->binding ) {
+               case ld::Fixup::bindingByNameUnbound:
+                       className = fit->u.name;
+                       break;
+               case ld::Fixup::bindingDirectlyBound:
+               case ld::Fixup::bindingByContentBound:
+                       className = fit->u.target->name();
+                       break;
+               case ld::Fixup::bindingsIndirectlyBound:
+                       className = ind.indirectName(fit->u.bindingIndex);
+                       break;
+               default:
+                       assert(0 && "unsupported binding in objc2 class ref section");
+       }
+       assert(className != NULL);
+       return className;
+}
+
+
+template <typename A>
+unsigned long ObjC2ClassRefsSection<A>::contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const
+{
+       unsigned long hash = 978;
+       for (const char* s = targetClassName(atom, ind); *s != '\0'; ++s) {
+               hash = hash * 33 + *s;
+       }
+       return hash;
+}
+
+template <typename A>
+bool ObjC2ClassRefsSection<A>::canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs, 
+                                                                                                       const ld::IndirectBindingTable& indirectBindingTable) const
+{
+       assert(this->type() == rhs.section().type());
+       const Atom<A>* rhsAtom = dynamic_cast<const Atom<A>*>(&rhs);
+       assert(rhsAtom !=  NULL);
+       const char* thisClassName = targetClassName(atom, indirectBindingTable);
+       const char* rhsClassName = targetClassName(rhsAtom, indirectBindingTable);
+       return (strcmp(thisClassName, rhsClassName) == 0);
+}
+
+
+template <typename A>
+const char* Objc1ClassReferences<A>::targetCString(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const
+{
+       assert(atom->fixupCount() == 2);
+       ld::Fixup::iterator fit = atom->fixupsBegin();
+       if ( fit->kind == ld::Fixup::kindSetTargetAddress )
+               ++fit;
+       const ld::Atom* targetAtom = NULL;
+       switch ( fit->binding ) {
+               case ld::Fixup::bindingByContentBound:
+                       targetAtom = fit->u.target;
+                       break;
+               case ld::Fixup::bindingsIndirectlyBound:
+                       targetAtom = ind.indirectAtom(fit->u.bindingIndex);
+                       if ( targetAtom == NULL ) {
+                               fprintf(stderr, "missing target named %s\n", ind.indirectName(fit->u.bindingIndex));
+                       }
+                       break;
+               default:
+                       assert(0);
+       }
+       assert(targetAtom != NULL);
+       const Atom<A>* target = dynamic_cast<const Atom<A>*>(targetAtom);
+       assert(target !=  NULL);
+       return (char*)target->contentPointer();
+}
+
+
+template <typename A>
+const char* PointerToCStringSection<A>::targetCString(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const
+{
+       assert(atom->fixupCount() == 1);
+       ld::Fixup::iterator fit = atom->fixupsBegin();
+       const ld::Atom* targetAtom = NULL;
+       switch ( fit->binding ) {
+               case ld::Fixup::bindingByContentBound:
+                       targetAtom = fit->u.target;
+                       break;
+               case ld::Fixup::bindingsIndirectlyBound:
+                       targetAtom = ind.indirectAtom(fit->u.bindingIndex);
+                       break;
+               default:
+                       assert(0);
+       }
+       assert(targetAtom != NULL);
+       const Atom<A>* target = dynamic_cast<const Atom<A>*>(targetAtom);
+       assert(target !=  NULL);
+       return (char*)target->contentPointer();
+}
+
+template <typename A>
+unsigned long PointerToCStringSection<A>::contentHash(const class Atom<A>* atom, 
+                                                                                                       const ld::IndirectBindingTable& indirectBindingTable) const
+{
+       // make hash from section name and target cstring name
+       unsigned long hash = 123;
+       for (const char* s = this->sectionName(); *s != '\0'; ++s) {
+               hash = hash * 33 + *s;
+       }
+       for (const char* s = this->targetCString(atom, indirectBindingTable); *s != '\0'; ++s) {
+               hash = hash * 33 + *s;
+       }
+       return hash;
+}
+
+template <typename A>
+bool PointerToCStringSection<A>::canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs, 
+                                                                                                       const ld::IndirectBindingTable& indirectBindingTable) const
+{
+       assert(this->type() == rhs.section().type());
+       // there can be pointers-to-cstrings in different section names
+       // we only want to coalesce in same section name
+       if ( *this != rhs.section() )
+               return false;
+       
+       // get string content for this 
+       const char* cstringContent = this->targetCString(atom, indirectBindingTable);
+       const Atom<A>* rhsAtom = dynamic_cast<const Atom<A>*>(&rhs);
+       assert(rhsAtom !=  NULL);
+       const char* rhsCstringContent = this->targetCString(rhsAtom, indirectBindingTable);
+
+       assert(cstringContent != NULL);
+       assert(rhsCstringContent != NULL);
+       return (strcmp(cstringContent, rhsCstringContent) == 0);
+}
+
+
+
+template <typename A>
+unsigned long UTF16StringSection<A>::contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const
+{
+       unsigned long hash = 5381;
+       const uint16_t* stringContent = (uint16_t*)atom->contentPointer();
+       // some buggy compilers end utf16 data with single byte, so don't use last word in hash computation
+       unsigned int count = (atom->size()/2) - 1;
+       for (const uint16_t* s = stringContent; count > 0; ++s, --count) {
+               hash = hash * 33 + *s;
+       }
+       return hash;
+}
+
+template <typename A>
+bool UTF16StringSection<A>::canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs, 
+                                                                                                       const ld::IndirectBindingTable& ind) const
+{
+       if ( rhs.section().type() != ld::Section::typeUTF16Strings )
+               return false;
+       assert(0);
+       return false;
+}
+
+
+
+
+
+
+
+template <>
+uint32_t Section<x86_64>::x86_64PcRelOffset(uint8_t r_type)
+{
+       switch ( r_type ) {
+               case X86_64_RELOC_SIGNED:
+                       return 4;
+               case X86_64_RELOC_SIGNED_1:
+                       return 5;
+               case X86_64_RELOC_SIGNED_2:
+                       return 6;
+               case X86_64_RELOC_SIGNED_4:
+                       return 8;
+       }
+       return 0;
+}
+
+
+template <>
+bool Section<x86_64>::addRelocFixup(class Parser<x86_64>& parser, const macho_relocation_info<P>* reloc)
+{
+       const macho_section<P>* sect = this->machoSection();
+       uint64_t srcAddr = sect->addr() + reloc->r_address();
+       Parser<x86_64>::SourceLocation  src;
+       Parser<x86_64>::TargetDesc              target;
+       Parser<x86_64>::TargetDesc              toTarget;
+       src.atom = this->findAtomByAddress(srcAddr);
+       src.offsetInAtom = srcAddr - src.atom->_objAddress;
+       const uint8_t* fixUpPtr = file().fileContent() + sect->offset() + reloc->r_address();
+       uint64_t contentValue = 0;
+       const macho_relocation_info<x86_64::P>* nextReloc = &reloc[1];
+       bool result = false;
+       bool useDirectBinding;
+       switch ( reloc->r_length() ) {
+               case 0:
+                       contentValue = *fixUpPtr;
+                       break;
+               case 1:
+                       contentValue = (int64_t)(int16_t)E::get16(*((uint16_t*)fixUpPtr));
+                       break;
+               case 2:
+                       contentValue = (int64_t)(int32_t)E::get32(*((uint32_t*)fixUpPtr));
+                       break;
+               case 3:
+                       contentValue = E::get64(*((uint64_t*)fixUpPtr));
+                       break;
+       }
+       target.atom = NULL;
+       target.name = NULL;
+       target.weakImport = false;
+       target.addend = 0;
+       if ( reloc->r_extern() ) {
+               const macho_nlist<P>& sym = parser.symbolFromIndex(reloc->r_symbolnum());
+               // use direct reference for local symbols
+               if ( ((sym.n_type() & N_TYPE) == N_SECT) && (((sym.n_type() & N_EXT) == 0) || (parser.nameFromSymbol(sym)[0] == 'L')) ) {
+                       parser.findTargetFromAddressAndSectionNum(sym.n_value(), sym.n_sect(), target);
+                       target.addend += contentValue;
+               }
+               else {
+                       target.name = parser.nameFromSymbol(sym);
+                       target.weakImport = parser.weakImportFromSymbol(sym);
+                       target.addend = contentValue;
+               }
+               // cfstrings should always use direct reference to backing store
+               if ( (this->type() == ld::Section::typeCFString) && (src.offsetInAtom != 0) ) {
+                       parser.findTargetFromAddressAndSectionNum(sym.n_value(), sym.n_sect(), target);
+                       target.addend = contentValue;
+               }
+       }
+       else {
+               if ( reloc->r_pcrel()  )
+                       contentValue += srcAddr + x86_64PcRelOffset(reloc->r_type());
+               parser.findTargetFromAddressAndSectionNum(contentValue, reloc->r_symbolnum(), target);
+       }
+       switch ( reloc->r_type() ) {
+               case X86_64_RELOC_UNSIGNED:
+                       if ( reloc->r_pcrel() )
+                               throw "pcrel and X86_64_RELOC_UNSIGNED not supported";
+                       switch ( reloc->r_length() ) {
+                               case 0:
+                               case 1:
+                                       throw "length < 2 and X86_64_RELOC_UNSIGNED not supported";
+                               case 2:
+                                       parser.addFixups(src, ld::Fixup::kindStoreLittleEndian32, target);
+                                       break;
+                               case 3:
+                                       parser.addFixups(src, ld::Fixup::kindStoreLittleEndian64, target);
+                                       break;
+                       }
+                       break;
+               case X86_64_RELOC_SIGNED:
+               case X86_64_RELOC_SIGNED_1:
+               case X86_64_RELOC_SIGNED_2:
+               case X86_64_RELOC_SIGNED_4:
+                       if ( ! reloc->r_pcrel() )
+                               throw "not pcrel and X86_64_RELOC_SIGNED* not supported";
+                       if ( reloc->r_length() != 2 ) 
+                               throw "length != 2 and X86_64_RELOC_SIGNED* not supported";
+                       switch ( reloc->r_type() ) {
+                               case X86_64_RELOC_SIGNED:
+                                       parser.addFixups(src, ld::Fixup::kindStoreX86PCRel32, target);
+                                       break;
+                               case X86_64_RELOC_SIGNED_1:
+                                       if ( reloc->r_extern() )
+                                               target.addend += 1;
+                                       parser.addFixups(src, ld::Fixup::kindStoreX86PCRel32_1, target);
+                                       break;  
+                               case X86_64_RELOC_SIGNED_2:
+                                       if ( reloc->r_extern() )
+                                               target.addend += 2;
+                                       parser.addFixups(src, ld::Fixup::kindStoreX86PCRel32_2, target);
+                                       break;  
+                               case X86_64_RELOC_SIGNED_4:
+                                       if ( reloc->r_extern() )
+                                               target.addend += 4;
+                                       parser.addFixups(src, ld::Fixup::kindStoreX86PCRel32_4, target);
+                                       break;
+                       }
+                       break;
+               case X86_64_RELOC_BRANCH:
+                       if ( ! reloc->r_pcrel() )
+                               throw "not pcrel and X86_64_RELOC_BRANCH not supported";
+                       switch ( reloc->r_length() ) {
+                               case 2:
+                                       if ( (target.name != NULL) && (strncmp(target.name, "___dtrace_probe$", 16) == 0) ) {
+                                               parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindStoreX86DtraceCallSiteNop, false, target.name);
+                                               parser.addDtraceExtraInfos(src, &target.name[16]);
+                                       }
+                                       else if ( (target.name != NULL) && (strncmp(target.name, "___dtrace_isenabled$", 20) == 0) ) {
+                                               parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindStoreX86DtraceIsEnableSiteClear, false, target.name);
+                                               parser.addDtraceExtraInfos(src, &target.name[20]);
+                                       }
+                                       else {
+                                               parser.addFixups(src, ld::Fixup::kindStoreX86BranchPCRel32, target);
+                                       }
+                                       break;
+                               case 0:
+                                       parser.addFixups(src, ld::Fixup::kindStoreX86BranchPCRel8, target);
+                                       break;
+                               default:
+                                       throwf("length=%d and X86_64_RELOC_BRANCH not supported", reloc->r_length());
+                       }
+                       break;
+               case X86_64_RELOC_GOT:
+                       if ( ! reloc->r_extern() ) 
+                               throw "not extern and X86_64_RELOC_GOT not supported";
+                       if ( ! reloc->r_pcrel() )
+                               throw "not pcrel and X86_64_RELOC_GOT not supported";
+                       if ( reloc->r_length() != 2 ) 
+                               throw "length != 2 and X86_64_RELOC_GOT not supported";
+                       parser.addFixups(src, ld::Fixup::kindStoreX86PCRel32GOT, target);
+                       break;
+               case X86_64_RELOC_GOT_LOAD:
+                       if ( ! reloc->r_extern() ) 
+                               throw "not extern and X86_64_RELOC_GOT_LOAD not supported";
+                       if ( ! reloc->r_pcrel() )
+                               throw "not pcrel and X86_64_RELOC_GOT_LOAD not supported";
+                       if ( reloc->r_length() != 2 ) 
+                               throw "length != 2 and X86_64_RELOC_GOT_LOAD not supported";
+                       parser.addFixups(src, ld::Fixup::kindStoreX86PCRel32GOTLoad, target);
+                       break;
+               case X86_64_RELOC_SUBTRACTOR:
+                       if ( reloc->r_pcrel() )
+                               throw "X86_64_RELOC_SUBTRACTOR cannot be pc-relative";
+                       if ( reloc->r_length() < 2 )
+                               throw "X86_64_RELOC_SUBTRACTOR must have r_length of 2 or 3";
+                       if ( !reloc->r_extern() )
+                               throw "X86_64_RELOC_SUBTRACTOR must have r_extern=1";
+                       if ( nextReloc->r_type() != X86_64_RELOC_UNSIGNED )
+                               throw "X86_64_RELOC_SUBTRACTOR must be followed by X86_64_RELOC_UNSIGNED";
+                       result = true;
+                       if ( nextReloc->r_pcrel() )
+                               throw "X86_64_RELOC_UNSIGNED following a X86_64_RELOC_SUBTRACTOR cannot be pc-relative";
+                       if ( nextReloc->r_length() != reloc->r_length() )
+                               throw "X86_64_RELOC_UNSIGNED following a X86_64_RELOC_SUBTRACTOR must have same r_length";
+                       if ( nextReloc->r_extern() ) {
+                               const macho_nlist<P>& sym = parser.symbolFromIndex(nextReloc->r_symbolnum());
+                               // use direct reference for local symbols
+                               if ( ((sym.n_type() & N_TYPE) == N_SECT) && (((sym.n_type() & N_EXT) == 0) || (parser.nameFromSymbol(sym)[0] == 'L')) ) {
+                                       parser.findTargetFromAddressAndSectionNum(sym.n_value(), sym.n_sect(), toTarget);
+                                       toTarget.addend = contentValue;
+                                       useDirectBinding = true;
+                               }
+                               else {
+                                       toTarget.name = parser.nameFromSymbol(sym);
+                                       toTarget.weakImport = parser.weakImportFromSymbol(sym);
+                                       toTarget.addend = contentValue;
+                                       useDirectBinding = false;
+                               }
+                       }
+                       else {
+                               parser.findTargetFromAddressAndSectionNum(contentValue, nextReloc->r_symbolnum(), toTarget);
+                               useDirectBinding = (toTarget.atom->scope() == ld::Atom::scopeTranslationUnit);
+                       }
+                       if ( useDirectBinding )
+                               parser.addFixup(src, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, toTarget.atom);
+                       else
+                               parser.addFixup(src, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, toTarget.weakImport, toTarget.name);
+                       parser.addFixup(src, ld::Fixup::k2of4, ld::Fixup::kindAddAddend, toTarget.addend);
+                       if ( target.atom == NULL )
+                               parser.addFixup(src, ld::Fixup::k3of4, ld::Fixup::kindSubtractTargetAddress, false, target.name);
+                       else
+                               parser.addFixup(src, ld::Fixup::k3of4, ld::Fixup::kindSubtractTargetAddress, target.atom);
+                       if ( reloc->r_length() == 2 )
+                               parser.addFixup(src, ld::Fixup::k4of4, ld::Fixup::kindStoreLittleEndian32);
+                       else
+                               parser.addFixup(src, ld::Fixup::k4of4, ld::Fixup::kindStoreLittleEndian64);
+                       break;
+               case X86_64_RELOC_TLV:
+                       if ( ! reloc->r_extern() ) 
+                               throw "not extern and X86_64_RELOC_TLV not supported";
+                       if ( ! reloc->r_pcrel() )
+                               throw "not pcrel and X86_64_RELOC_TLV not supported";
+                       if ( reloc->r_length() != 2 ) 
+                               throw "length != 2 and X86_64_RELOC_TLV not supported";
+                       parser.addFixups(src, ld::Fixup::kindStoreX86PCRel32TLVLoad, target);
+                       break;
+               default:
+                       throwf("unknown relocation type %d", reloc->r_type());
+       }
+       return result;
+}
+
+
+
+template <>
+bool Section<x86>::addRelocFixup(class Parser<x86>& parser, const macho_relocation_info<P>* reloc)
+{
+       const macho_section<P>* sect = this->machoSection();
+       uint32_t srcAddr;
+       const uint8_t* fixUpPtr;
+       uint32_t contentValue = 0;
+       ld::Fixup::Kind kind = ld::Fixup::kindNone;
+       Parser<x86>::SourceLocation     src;
+       Parser<x86>::TargetDesc         target;
+
+       if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
+               srcAddr = sect->addr() + reloc->r_address();
+               src.atom = this->findAtomByAddress(srcAddr);
+               src.offsetInAtom = srcAddr - src.atom->_objAddress;
+               fixUpPtr = file().fileContent() + sect->offset() + reloc->r_address();
+               switch ( reloc->r_type() ) {
+               case GENERIC_RELOC_VANILLA:
+                       switch ( reloc->r_length() ) {
+                               case 0:
+                                       contentValue = (int32_t)(int8_t)*fixUpPtr;
+                                       if ( reloc->r_pcrel() ) {
+                                               kind = ld::Fixup::kindStoreX86BranchPCRel8;
+                                               contentValue += srcAddr + sizeof(uint8_t);
+                                       }
+                                       else
+                                               throw "r_length=0 and r_pcrel=0 not supported";
+                                       break;
+                               case 1:
+                                       contentValue = (int32_t)(int16_t)E::get16(*((uint16_t*)fixUpPtr));
+                                       if ( reloc->r_pcrel() ) {
+                                               kind = ld::Fixup::kindStoreX86PCRel16;
+                                               contentValue += srcAddr + sizeof(uint16_t);
+                                       }
+                                       else
+                                               kind = ld::Fixup::kindStoreLittleEndian16;
+                                       break;
+                               case 2:
+                                       contentValue = E::get32(*((uint32_t*)fixUpPtr));
+                                       if ( reloc->r_pcrel() ) {
+                                               kind = ld::Fixup::kindStoreX86BranchPCRel32;
+                                               contentValue += srcAddr + sizeof(uint32_t);
+                                       }
+                                       else
+                                               kind = ld::Fixup::kindStoreLittleEndian32;
+                                       break;
+                               case 3:
+                                       throw "r_length=3 not supported";
+                       }
+                       if ( reloc->r_extern() ) {
+                               target.atom = NULL;
+                               const macho_nlist<P>& targetSymbol = parser.symbolFromIndex(reloc->r_symbolnum());
+                               target.name = parser.nameFromSymbol(targetSymbol);
+                               target.weakImport = parser.weakImportFromSymbol(targetSymbol);
+                               target.addend = contentValue;
+                       }
+                       else {
+                               parser.findTargetFromAddressAndSectionNum(contentValue, reloc->r_symbolnum(), target);
+                       }
+                       if ( (kind == ld::Fixup::kindStoreX86BranchPCRel32) && (target.name != NULL) ) {
+                               if ( strncmp(target.name, "___dtrace_probe$", 16) == 0 ) {
+                                       parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindStoreX86DtraceCallSiteNop, false, target.name);
+                                       parser.addDtraceExtraInfos(src, &target.name[16]);
+                                       return false;
+                               }
+                               else if ( strncmp(target.name, "___dtrace_isenabled$", 20) == 0 ) {
+                                       parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindStoreX86DtraceIsEnableSiteClear, false, target.name);
+                                       parser.addDtraceExtraInfos(src, &target.name[20]);
+                                       return false;
+                               }
+                       }
+                       parser.addFixups(src, kind, target);
+                       return false;
+                       break;
+               case GENERIC_RLEOC_TLV:
+                       {
+                               if ( !reloc->r_extern() )
+                                       throw "r_extern=0 and r_type=GENERIC_RLEOC_TLV not supported";
+                               if ( reloc->r_length() != 2 )
+                                       throw "r_length!=2 and r_type=GENERIC_RLEOC_TLV not supported";
+                               const macho_nlist<P>& sym = parser.symbolFromIndex(reloc->r_symbolnum());
+                               // use direct reference for local symbols
+                               if ( ((sym.n_type() & N_TYPE) == N_SECT) && ((sym.n_type() & N_EXT) == 0) ) {
+                                       parser.findTargetFromAddressAndSectionNum(sym.n_value(), sym.n_sect(), target);
+                               }
+                               else {
+                                       target.atom = NULL;
+                                       target.name = parser.nameFromSymbol(sym);
+                                       target.weakImport = parser.weakImportFromSymbol(sym);
+                               }                       
+                               target.addend = (int64_t)(int32_t)E::get32(*((uint32_t*)fixUpPtr));
+                               if ( reloc->r_pcrel() ) {
+                                       parser.addFixups(src, ld::Fixup::kindStoreX86PCRel32TLVLoad, target);
+                               }
+                               else {
+                                       parser.addFixups(src, ld::Fixup::kindStoreX86Abs32TLVLoad, target);
+                               }
+                               return false;
+                       }
+                       break;
+               default:
+                       throwf("unsupported i386 relocation type (%d)", reloc->r_type());
+               }
+       }
+       else {
+               // scattered relocation
+               const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
+               srcAddr = sect->addr() + sreloc->r_address();
+               src.atom = this->findAtomByAddress(srcAddr);
+               src.offsetInAtom = srcAddr - src.atom->_objAddress;
+               fixUpPtr = file().fileContent() + sect->offset() + sreloc->r_address();
+               uint32_t relocValue = sreloc->r_value();
+               bool result = false;
+               // file format allows pair to be scattered or not
+               const macho_scattered_relocation_info<P>* nextSReloc = &sreloc[1];
+               const macho_relocation_info<P>* nextReloc = &reloc[1];
+               bool nextRelocIsPair = false;
+               uint32_t nextRelocAddress = 0;
+               uint32_t nextRelocValue = 0;
+               if ( (nextReloc->r_address() & R_SCATTERED) == 0 ) {
+                       if ( nextReloc->r_type() == GENERIC_RELOC_PAIR ) {
+                               nextRelocIsPair = true;
+                               nextRelocAddress = nextReloc->r_address();
+                               result = true;  // iterator should skip next reloc, since we've consumed it here
+                       }
+               }
+               else {
+                       if ( nextSReloc->r_type() == GENERIC_RELOC_PAIR ) {
+                               nextRelocIsPair = true;
+                               nextRelocAddress = nextSReloc->r_address();
+                               nextRelocValue = nextSReloc->r_value();
+                       }
+               }
+               switch (sreloc->r_type()) {
+                       case GENERIC_RELOC_VANILLA:
+                               // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
+                               target.atom = parser.findAtomByAddress(relocValue);
+                               if ( sreloc->r_pcrel() ) {
+                                       switch ( sreloc->r_length() ) {
+                                               case 0:
+                                                       contentValue = srcAddr + 1 + *fixUpPtr;
+                                                       target.addend = contentValue - relocValue;
+                                                       parser.addFixups(src, ld::Fixup::kindStoreX86PCRel8, target);
+                                                       break;
+                                               case 1:
+                                                       contentValue = srcAddr + 2 + LittleEndian::get16(*((uint16_t*)fixUpPtr));
+                                                       target.addend = contentValue - relocValue;
+                                                       parser.addFixups(src, ld::Fixup::kindStoreX86PCRel16, target);
+                                                       break;
+                                               case 2:
+                                                       contentValue = srcAddr + 4 + LittleEndian::get32(*((uint32_t*)fixUpPtr));
+                                                       target.addend = contentValue - relocValue;
+                                                       parser.addFixups(src, ld::Fixup::kindStoreX86PCRel32, target);
+                                                       break;
+                                               case 3:
+                                                       throw "unsupported r_length=3 for scattered pc-rel vanilla reloc";
+                                                       break;
+                                       }
+                               }
+                               else {
+                                       if ( sreloc->r_length() != 2 )
+                                               throwf("unsupported r_length=%d for scattered vanilla reloc", sreloc->r_length());
+                                       contentValue = LittleEndian::get32(*((uint32_t*)fixUpPtr));
+                                       target.addend = contentValue - target.atom->objectAddress();
+                                       parser.addFixups(src, ld::Fixup::kindStoreLittleEndian32, target);
+                               }
+                               break;
+                       case GENERIC_RELOC_SECTDIFF:
+                       case GENERIC_RELOC_LOCAL_SECTDIFF:
+                               {
+                                       if ( !nextRelocIsPair ) 
+                                               throw "GENERIC_RELOC_SECTDIFF missing following pair";
+                                       switch ( sreloc->r_length() ) {
+                                               case 0:
+                                               case 3:
+                                                       throw "bad length for GENERIC_RELOC_SECTDIFF";
+                                               case 1:
+                                                       contentValue = (int32_t)(int16_t)LittleEndian::get16(*((uint16_t*)fixUpPtr));
+                                                       kind = ld::Fixup::kindStoreLittleEndian16;
+                                                       break;
+                                               case 2:
+                                                       contentValue = LittleEndian::get32(*((uint32_t*)fixUpPtr));
+                                                       kind = ld::Fixup::kindStoreLittleEndian32;
+                                                       break;
+                                       }
+                                       Atom<x86>* fromAtom  = parser.findAtomByAddress(nextRelocValue);
+                                       uint32_t offsetInFrom = nextRelocValue - fromAtom->_objAddress;
+                                       parser.findTargetFromAddress(sreloc->r_value(), target);
+                                       // check for addend encoded in the section content
+                                       int32_t addend = contentValue - (sreloc->r_value() - nextRelocValue);
+                                       if ( addend < 0 ) {
+                                               // switch binding base on coalescing
+                                               if ( target.atom == NULL ) {
+                                                       parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, false, target.name);
+                                               }
+                                               else if ( target.atom->scope() == ld::Atom::scopeTranslationUnit ) {
+                                                       parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, target.atom);
+                                               }
+                                               else if ( (target.atom->combine() == ld::Atom::combineByNameAndContent) || (target.atom->combine() == ld::Atom::combineByNameAndReferences) ) {
+                                                       parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, ld::Fixup::bindingByContentBound, target.atom);
+                                               }
+                                               else {
+                                                       parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, false, target.atom->name());
+                                               }
+                                               parser.addFixup(src, ld::Fixup::k2of5, ld::Fixup::kindAddAddend, target.addend);
+                                               parser.addFixup(src, ld::Fixup::k3of5, ld::Fixup::kindSubtractTargetAddress, fromAtom);
+                                               parser.addFixup(src, ld::Fixup::k4of5, ld::Fixup::kindSubtractAddend, offsetInFrom-addend);
+                                               parser.addFixup(src, ld::Fixup::k5of5, kind);
+                                       }
+                                       else {
+                                               // switch binding base on coalescing
+                                               if ( target.atom == NULL ) {
+                                                       parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, false, target.name);
+                                               }
+                                               else if ( target.atom->scope() == ld::Atom::scopeTranslationUnit ) {
+                                                       parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, target.atom);
+                                               }
+                                               else if ( (target.atom->combine() == ld::Atom::combineByNameAndContent) || (target.atom->combine() == ld::Atom::combineByNameAndReferences) ) {
+                                                       parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, ld::Fixup::bindingByContentBound, target.atom);
+                                               }
+                                               else {
+                                                       parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, false, target.atom->name());
+                                               }
+                                               parser.addFixup(src, ld::Fixup::k2of5, ld::Fixup::kindAddAddend, target.addend+addend);
+                                               parser.addFixup(src, ld::Fixup::k3of5, ld::Fixup::kindSubtractTargetAddress, fromAtom);
+                                               parser.addFixup(src, ld::Fixup::k4of5, ld::Fixup::kindSubtractAddend, offsetInFrom);
+                                               parser.addFixup(src, ld::Fixup::k5of5, kind);
+                                       }
+                               }
+                               break;
+               }
+               return result;
+       }
+}
+
+
+       
+//
+// ppc and ppc64 both use the same relocations, so process them in one common routine
+//
+template <typename A>
+bool Section<A>::addRelocFixup_powerpc(class Parser<A>& parser,
+                                                                                 const macho_relocation_info<typename A::P>* reloc)
+{
+       const macho_section<P>* sect = this->machoSection();
+       bool result = false;
+       uint32_t srcAddr;
+       uint32_t dstAddr;
+       uint32_t* fixUpPtr;
+       int32_t displacement = 0;
+       uint32_t instruction = 0;
+       int16_t lowBits;
+       pint_t contentValue = 0;
+       typename Parser<A>::SourceLocation      src;
+       typename Parser<A>::TargetDesc          target;
+       
+       if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
+               srcAddr = sect->addr() + reloc->r_address();
+               src.atom = this->findAtomByAddress(srcAddr);
+               src.offsetInAtom = srcAddr - src.atom->_objAddress;
+               const macho_relocation_info<P>* nextReloc = &reloc[1];
+               fixUpPtr = (uint32_t*)(file().fileContent() + sect->offset() + reloc->r_address());
+               if ( reloc->r_type() != PPC_RELOC_PAIR )
+                       instruction = BigEndian::get32(*fixUpPtr);
+               if ( reloc->r_extern() ) {
+                       target.atom = NULL;
+                       const macho_nlist<P>& targetSymbol = parser.symbolFromIndex(reloc->r_symbolnum());
+                       target.name = parser.nameFromSymbol(targetSymbol);
+                       target.weakImport = parser.weakImportFromSymbol(targetSymbol);
+               }
+               switch ( reloc->r_type() ) {
+                       case PPC_RELOC_BR24:
+                               assert((instruction & 0x4C000000) == 0x48000000);
+                               displacement = (instruction & 0x03FFFFFC);
+                               if ( (displacement & 0x02000000) != 0 )
+                                       displacement |= 0xFC000000;
+                               if ( reloc->r_extern() ) {
+                                       target.addend = srcAddr + displacement;
+                               }
+                               else {
+                                       dstAddr = srcAddr + displacement;
+                                       parser.findTargetFromAddressAndSectionNum(dstAddr, reloc->r_symbolnum(), target);
+                               }
+                               // special case "calls" for dtrace 
+                               if ( (target.name != NULL) && (strncmp(target.name, "___dtrace_probe$", 16) == 0) ) {
+                                       parser.addFixup(src, ld::Fixup::k1of1,
+                                                                                                                       ld::Fixup::kindStorePPCDtraceCallSiteNop, false, target.name);
+                                       parser.addDtraceExtraInfos(src, &target.name[16]);
+                               }
+                               else if ( (target.name != NULL) && (strncmp(target.name, "___dtrace_isenabled$", 20) == 0) ) {
+                                       parser.addFixup(src, ld::Fixup::k1of1, 
+                                                                                                                       ld::Fixup::kindStorePPCDtraceIsEnableSiteClear, false, target.name);
+                                       parser.addDtraceExtraInfos(src, &target.name[20]);
+                               }
+                               else {
+                                       parser.addFixups(src, ld::Fixup::kindStorePPCBranch24, target);
+                               }
+                               break;
+                       case PPC_RELOC_BR14:
+                               displacement = (instruction & 0x0000FFFC);
+                               if ( (displacement & 0x00008000) != 0 )
+                                       displacement |= 0xFFFF0000;
+                               if ( reloc->r_extern() ) {
+                                       target.addend = srcAddr + displacement;
+                               }
+                               else {
+                                       dstAddr = srcAddr + displacement;
+                                       parser.findTargetFromAddressAndSectionNum(dstAddr, reloc->r_symbolnum(), target);
+                               }
+                               parser.addFixups(src, ld::Fixup::kindStorePPCBranch14, target);
+                               break;
+                       case PPC_RELOC_PAIR:
+                               // skip, processed by a previous look ahead
+                               break;
+                       case PPC_RELOC_LO16:
+                               if ( nextReloc->r_type() != PPC_RELOC_PAIR ) 
+                                       throw "PPC_RELOC_LO16 missing following pair";
+                               result = true;
+                               lowBits = (instruction & 0x0000FFFF);
+                               dstAddr = (nextReloc->r_address() << 16) + ((uint32_t)lowBits & 0x0000FFFF);
+                               if ( reloc->r_extern() ) {
+                                       target.addend = dstAddr;
+                               }
+                               else {
+                                       parser.findTargetFromAddressAndSectionNum(dstAddr, reloc->r_symbolnum(), target);
+                               }
+                               parser.addFixups(src, ld::Fixup::kindStorePPCAbsLow16, target);
+                               break;
+                       case PPC_RELOC_LO14:
+                               if ( nextReloc->r_type() != PPC_RELOC_PAIR ) 
+                                       throw "PPC_RELOC_LO14 missing following pair";
+                               result = true;
+                               lowBits = (instruction & 0xFFFC);
+                               dstAddr = (nextReloc->r_address() << 16) + ((uint32_t)lowBits & 0x0000FFFF);
+                               if ( reloc->r_extern() ) {
+                                       target.addend = dstAddr;
+                               }
+                               else {
+                                       parser.findTargetFromAddressAndSectionNum(dstAddr, reloc->r_symbolnum(), target);
+                               }
+                               parser.addFixups(src, ld::Fixup::kindStorePPCAbsLow14, target);
+                               break;
+                       case PPC_RELOC_HI16:
+                               if ( nextReloc->r_type() != PPC_RELOC_PAIR ) 
+                                       throw "PPC_RELOC_HI16 missing following pair";
+                               result = true;
+                               lowBits = (nextReloc->r_address() & 0xFFFF);
+                               dstAddr = ((instruction & 0xFFFF) << 16) | (lowBits & 0x0000FFFF);
+                               if ( reloc->r_extern() ) {
+                                       target.addend = dstAddr;
+                               }
+                               else {
+                                       parser.findTargetFromAddressAndSectionNum(dstAddr, reloc->r_symbolnum(), target);
+                               }
+                               parser.addFixups(src, ld::Fixup::kindStorePPCAbsHigh16, target);
+                               break;
+                       case PPC_RELOC_HA16:
+                               if ( nextReloc->r_type() != PPC_RELOC_PAIR ) 
+                                       throw "PPC_RELOC_HA16 missing following pair";
+                               result = true;
+                               lowBits = (nextReloc->r_address() & 0x0000FFFF);
+                               dstAddr = ((instruction & 0xFFFF) << 16) + (int32_t)lowBits;
+                               if ( reloc->r_extern() ) {
+                                       target.addend = dstAddr;
+                               }
+                               else {
+                                       parser.findTargetFromAddressAndSectionNum(dstAddr, reloc->r_symbolnum(), target);
+                               }
+                               parser.addFixups(src, ld::Fixup::kindStorePPCAbsHigh16AddLow, target);
+                               break;
+                       case PPC_RELOC_VANILLA:
+                               contentValue = P::getP(*((pint_t*)fixUpPtr));
+                               if ( reloc->r_extern() ) {
+                                       target.addend = contentValue;
+                               }
+                               else {
+                                       parser.findTargetFromAddressAndSectionNum(contentValue, reloc->r_symbolnum(), target);
+                               }
+                               switch ( reloc->r_length() ) {
+                                       case 0:
+                                       case 1:
+                                               throw "bad r_length in PPC_RELOC_VANILLA";
+                                       case 2:
+                                               parser.addFixups(src, ld::Fixup::kindStoreBigEndian32, target);
+                                               break;
+                                       case 3:
+                                               parser.addFixups(src, ld::Fixup::kindStoreBigEndian64, target);
+                                               break;
+                               }
+                               break;
+                       case PPC_RELOC_JBSR:
+                               // this is from -mlong-branch codegen.  We ignore the jump island and make reference to the real target
+                               if ( nextReloc->r_type() != PPC_RELOC_PAIR ) 
+                                       throw "PPC_RELOC_JBSR missing following pair";
+                               if ( !parser._hasLongBranchStubs )
+                                       warning("object file compiled with -mlong-branch which is no longer needed. "
+                                                       "To remove this warning, recompile without -mlong-branch: %s", parser._path);
+                               parser._hasLongBranchStubs = true;
+                               result = true;
+                               if ( reloc->r_extern() ) {
+                                       throw "PPC_RELOC_JBSR should not be using an external relocation";
+                               }
+                               parser.findTargetFromAddressAndSectionNum(nextReloc->r_address(), reloc->r_symbolnum(), target);
+                               parser.addFixups(src, ld::Fixup::kindStorePPCBranch24, target);
+                               break;
+                       default:
+                               warning("unknown relocation type %d", reloc->r_type());
+               }
+       }
+       else {
+               const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
+               // file format allows pair to be scattered or not
+               const macho_scattered_relocation_info<P>* nextSReloc = &sreloc[1];
+               const macho_relocation_info<P>* nextReloc = &reloc[1];
+               srcAddr = sect->addr() + sreloc->r_address();
+               dstAddr = sreloc->r_value();
+               fixUpPtr = (uint32_t*)(file().fileContent() + sect->offset() + sreloc->r_address());
+               instruction = BigEndian::get32(*fixUpPtr);
+               src.atom = this->findAtomByAddress(srcAddr);
+               src.offsetInAtom = srcAddr - src.atom->_objAddress;
+               typename Parser<A>::TargetDesc          picBase;
+               bool nextRelocIsPair = false;
+               uint32_t nextRelocAddress = 0;
+               uint32_t nextRelocValue = 0;
+               if ( (nextReloc->r_address() & R_SCATTERED) == 0 ) {
+                       if ( nextReloc->r_type() == PPC_RELOC_PAIR ) {
+                               nextRelocIsPair = true;
+                               nextRelocAddress = nextReloc->r_address();
+                               result = true;
+                       }
+               }
+               else {
+                       if ( nextSReloc->r_type() == PPC_RELOC_PAIR ) {
+                               nextRelocIsPair = true;
+                               nextRelocAddress = nextSReloc->r_address();
+                               nextRelocValue = nextSReloc->r_value();
+                               result = true;
+                       }
+               }
+               switch ( sreloc->r_type() ) {
+                       case PPC_RELOC_VANILLA:
+                               // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
+                               target.atom = parser.findAtomByAddress(sreloc->r_value());
+                               switch ( sreloc->r_length() ) {
+                                       case 0:
+                                       case 1:
+                                               throw "unsuppored r_length < 2 for scattered PPC_RELOC_VANILLA";
+                                       case 2:
+                                               contentValue = BigEndian::get32(*(uint32_t*)fixUpPtr);
+                                               target.addend = contentValue - target.atom->_objAddress;
+                                               parser.addFixups(src, ld::Fixup::kindStoreBigEndian32, target);
+                                               break;
+                                       case 3:
+                                               contentValue = BigEndian::get64(*(uint64_t*)fixUpPtr);
+                                               target.addend = contentValue - target.atom->_objAddress;
+                                               parser.addFixups(src, ld::Fixup::kindStoreBigEndian64, target);
+                                               break;
+                               }
+                               break;
+                       case PPC_RELOC_BR14:
+                               displacement = (instruction & 0x0000FFFC);
+                               if ( (displacement & 0x00008000) != 0 )
+                                       displacement |= 0xFFFF0000;
+                               target.atom = parser.findAtomByAddress(sreloc->r_value());
+                               target.addend = (srcAddr + displacement) - target.atom->_objAddress;
+                               parser.addFixups(src, ld::Fixup::kindStorePPCBranch14, target);
+                               break;
+                       case PPC_RELOC_BR24:
+                               assert((instruction & 0x4C000000) == 0x48000000);
+                               displacement = (instruction & 0x03FFFFFC);
+                               if ( (displacement & 0x02000000) != 0 )
+                                       displacement |= 0xFC000000;
+                               target.atom = parser.findAtomByAddress(sreloc->r_value());
+                               target.addend = (srcAddr + displacement) - target.atom->_objAddress;
+                               parser.addFixups(src, ld::Fixup::kindStorePPCBranch24, target);
+                               break;
+                       case PPC_RELOC_LO16_SECTDIFF:
+                               if ( ! nextRelocIsPair ) 
+                                       throw "PPC_RELOC_LO16_SECTDIFF missing following pair";
+                               lowBits = (instruction & 0xFFFF);
+                               dstAddr = nextRelocValue + ((nextRelocAddress << 16) | ((uint32_t)lowBits & 0x0000FFFF));
+                               parser.findTargetFromAddress(sreloc->r_value(), target);
+                               if ( target.atom != NULL )
+                                       target.addend = dstAddr - target.atom->_objAddress;
+                               picBase.atom = parser.findAtomByAddress(nextRelocValue);
+                               picBase.addend = nextRelocValue - picBase.atom->_objAddress;
+                               picBase.weakImport = false;
+                               picBase.name = NULL;
+                               parser.addFixups(src, ld::Fixup::kindStorePPCPicLow16, target, picBase);
+                               break;
+                       case PPC_RELOC_LO14_SECTDIFF:
+                               if ( ! nextRelocIsPair ) 
+                                       throw "PPC_RELOC_LO14_SECTDIFF missing following pair";
+                               lowBits = (instruction & 0xFFFC);
+                               dstAddr = nextRelocValue + ((nextRelocAddress << 16) | ((uint32_t)lowBits & 0x0000FFFF));
+                               parser.findTargetFromAddress(sreloc->r_value(), target);
+                               if ( target.atom != NULL )
+                                       target.addend = dstAddr - target.atom->_objAddress;
+                               picBase.atom = parser.findAtomByAddress(nextRelocValue);
+                               picBase.addend = nextRelocValue - picBase.atom->_objAddress;
+                               picBase.weakImport = false;
+                               picBase.name = NULL;
+                               parser.addFixups(src, ld::Fixup::kindStorePPCPicLow14, target, picBase);
+                               break;
+                       case PPC_RELOC_HA16_SECTDIFF:
+                               if ( ! nextRelocIsPair ) 
+                                       throw "PPC_RELOC_HA16_SECTDIFF missing following pair";
+                               lowBits = (nextRelocAddress & 0x0000FFFF);
+                               dstAddr = nextRelocValue + (((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits);
+                               parser.findTargetFromAddress(sreloc->r_value(), target);
+                               if ( target.atom != NULL )
+                                       target.addend = dstAddr - target.atom->_objAddress;
+                               picBase.atom = parser.findAtomByAddress(nextRelocValue);
+                               picBase.addend = nextRelocValue - picBase.atom->_objAddress;
+                               picBase.weakImport = false;
+                               picBase.name = NULL;
+                               parser.addFixups(src, ld::Fixup::kindStorePPCPicHigh16AddLow, target, picBase);
+                               break;
+                       case PPC_RELOC_LO14:
+                               if ( ! nextRelocIsPair )
+                                       throw "PPC_RELOC_LO14 missing following pair";
+                               lowBits = (instruction & 0xFFFC);
+                               dstAddr = ((nextRelocAddress << 16) + ((uint32_t)lowBits & 0x0000FFFF));
+                               parser.findTargetFromAddress(sreloc->r_value(), dstAddr, target);
+                               parser.addFixups(src, ld::Fixup::kindStorePPCAbsLow14, target);
+                               break;
+                       case PPC_RELOC_LO16:
+                               if ( ! nextRelocIsPair )
+                                       throw "PPC_RELOC_LO16 missing following pair";
+                               lowBits = (instruction & 0xFFFF);
+                               dstAddr = ((nextRelocAddress << 16) + ((uint32_t)lowBits & 0x0000FFFF));
+                               parser.findTargetFromAddress(sreloc->r_value(), dstAddr, target);
+                               parser.addFixups(src, ld::Fixup::kindStorePPCAbsLow16, target);
+                               break;
+                       case PPC_RELOC_HA16:
+                               if ( ! nextRelocIsPair ) 
+                                       throw "PPC_RELOC_HA16 missing following pair";
+                               lowBits = (nextRelocAddress & 0xFFFF);
+                               dstAddr = (((instruction & 0xFFFF) << 16) + (int32_t)lowBits);
+                               parser.findTargetFromAddress(sreloc->r_value(), dstAddr, target);
+                               parser.addFixups(src, ld::Fixup::kindStorePPCAbsHigh16AddLow, target);
+                               break;
+                       case PPC_RELOC_HI16:
+                               if ( ! nextRelocIsPair )
+                                       throw "PPC_RELOC_HI16 missing following pair";
+                               lowBits = (nextRelocAddress & 0xFFFF);
+                               dstAddr = ((instruction & 0xFFFF) << 16) | (lowBits & 0x0000FFFF);
+                               parser.findTargetFromAddress(sreloc->r_value(), dstAddr, target);
+                               parser.addFixups(src, ld::Fixup::kindStorePPCAbsHigh16, target);
+                               break;
+                       case PPC_RELOC_SECTDIFF:
+                       case PPC_RELOC_LOCAL_SECTDIFF:
+                               {
+                                       if ( ! nextRelocIsPair ) 
+                                               throw "PPC_RELOC_SECTDIFF missing following pair";
+                                       ld::Fixup::Kind kind = ld::Fixup::kindNone;
+                                       switch ( sreloc->r_length() ) {
+                                               case 0:
+                                                       throw "bad length for PPC_RELOC_SECTDIFF";
+                                               case 1:
+                                                       contentValue = (int32_t)(int16_t)BigEndian::get16(*((uint16_t*)fixUpPtr));
+                                                       kind = ld::Fixup::kindStoreBigEndian16;
+                                                       break;
+                                               case 2:
+                                                       contentValue = BigEndian::get32(*((uint32_t*)fixUpPtr));
+                                                       kind = ld::Fixup::kindStoreBigEndian32;
+                                                       break;
+                                               case 3:
+                                                       contentValue = BigEndian::get64(*((uint64_t*)fixUpPtr));
+                                                       kind = ld::Fixup::kindStoreBigEndian64;
+                                                       break;
+                                               break;
+                                       }
+                                       Atom<A>* fromAtom  = parser.findAtomByAddress(nextRelocValue);
+                                       Atom<A>* targetAtom = parser.findAtomByAddress(sreloc->r_value());
+                                       uint32_t offsetInFrom = nextRelocValue - fromAtom->_objAddress;
+                                       uint32_t offsetInTarget = sreloc->r_value() - targetAtom->_objAddress;
+                                       // check for addend encoded in the section content
+                                       int32_t addend = contentValue - (sreloc->r_value() - nextRelocValue);
+                                       if ( addend < 0 ) {
+                                               if ( targetAtom->scope() == ld::Atom::scopeTranslationUnit ) {
+                                                       parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, targetAtom);
+                                               }
+                                               else if ( (targetAtom->combine() == ld::Atom::combineByNameAndContent) || (targetAtom->combine() == ld::Atom::combineByNameAndReferences) ) {
+                                                       parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, ld::Fixup::bindingByContentBound, targetAtom);
+                                               }
+                                               else {
+                                                       parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, false, targetAtom->name());
+                                               }
+                                               parser.addFixup(src, ld::Fixup::k2of5, ld::Fixup::kindAddAddend, offsetInTarget);
+                                               parser.addFixup(src, ld::Fixup::k3of5, ld::Fixup::kindSubtractTargetAddress, fromAtom);
+                                               parser.addFixup(src, ld::Fixup::k4of5, ld::Fixup::kindSubtractAddend, offsetInFrom-addend);
+                                               parser.addFixup(src, ld::Fixup::k5of5, kind);
+                                       }
+                                       else {
+                                               if ( targetAtom->scope() == ld::Atom::scopeTranslationUnit ) {
+                                                       parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, targetAtom);
+                                               }
+                                               else if ( (targetAtom->combine() == ld::Atom::combineByNameAndContent) || (targetAtom->combine() == ld::Atom::combineByNameAndReferences) ) {
+                                                       parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, ld::Fixup::bindingByContentBound, targetAtom);
+                                               }
+                                               else {
+                                                       parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, false, targetAtom->name());
+                                               }
+                                               parser.addFixup(src, ld::Fixup::k2of5, ld::Fixup::kindAddAddend, offsetInTarget+addend);
+                                               parser.addFixup(src, ld::Fixup::k3of5, ld::Fixup::kindSubtractTargetAddress, fromAtom);
+                                               parser.addFixup(src, ld::Fixup::k4of5, ld::Fixup::kindSubtractAddend, offsetInFrom);
+                                               parser.addFixup(src, ld::Fixup::k5of5, kind);
+                                       }
+                               }
+                               break;
+                       case PPC_RELOC_PAIR:
+                               break;
+                       case PPC_RELOC_HI16_SECTDIFF:
+                               warning("unexpected scattered relocation type PPC_RELOC_HI16_SECTDIFF");
+                               break;
+                       default:
+                               warning("unknown scattered relocation type %d", sreloc->r_type());
+               }
+       }
+       return result;
+}
+
+
+template <>
+bool Section<ppc>::addRelocFixup(class Parser<ppc>& parser, const macho_relocation_info<P>* reloc)
+{
+       return addRelocFixup_powerpc(parser, reloc);
+}
+
+
+template <>
+bool Section<ppc64>::addRelocFixup(class Parser<ppc64>& parser, const macho_relocation_info<P>* reloc)
+{
+       return addRelocFixup_powerpc(parser, reloc);
+}
+
+
+
+template <>
+bool Section<arm>::addRelocFixup(class Parser<arm>& parser, const macho_relocation_info<P>* reloc)
+{
+       const macho_section<P>* sect = this->machoSection();
+       bool result = false;
+       uint32_t srcAddr;
+       uint32_t dstAddr;
+       uint32_t* fixUpPtr;
+       int32_t displacement = 0;
+       uint32_t instruction = 0;
+       pint_t contentValue = 0;
+       Parser<arm>::SourceLocation     src;
+       Parser<arm>::TargetDesc         target;
+       const macho_relocation_info<P>* nextReloc;
+       
+       if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
+               bool externSymbolIsThumbDef = false;
+               srcAddr = sect->addr() + reloc->r_address();
+               src.atom = this->findAtomByAddress(srcAddr);
+               src.offsetInAtom = srcAddr - src.atom->_objAddress;
+               fixUpPtr = (uint32_t*)(file().fileContent() + sect->offset() + reloc->r_address());
+               if ( reloc->r_type() != ARM_RELOC_PAIR )
+                       instruction = LittleEndian::get32(*fixUpPtr);
+               if ( reloc->r_extern() ) {
+                       target.atom = NULL;
+                       const macho_nlist<P>& targetSymbol = parser.symbolFromIndex(reloc->r_symbolnum());
+                       target.name = parser.nameFromSymbol(targetSymbol);
+                       target.weakImport = parser.weakImportFromSymbol(targetSymbol);
+                       if ( ((targetSymbol.n_type() & N_TYPE) == N_SECT) &&  (targetSymbol.n_desc() & N_ARM_THUMB_DEF) )
+                               externSymbolIsThumbDef = true;
+               }
+               switch ( reloc->r_type() ) {
+                       case ARM_RELOC_BR24:
+                               // Sign-extend displacement
+                               displacement = (instruction & 0x00FFFFFF) << 2;
+                               if ( (displacement & 0x02000000) != 0 )
+                                       displacement |= 0xFC000000;
+                               // The pc added will be +8 from the pc
+                               displacement += 8;
+                               // If this is BLX add H << 1
+                               if ((instruction & 0xFE000000) == 0xFA000000)
+                                       displacement += ((instruction & 0x01000000) >> 23);
+                               if ( reloc->r_extern() ) {
+                                       target.addend = srcAddr + displacement;
+                                       if ( externSymbolIsThumbDef )
+                                               target.addend &= -2; // remove thumb bit
+                               }
+                               else {
+                                       dstAddr = srcAddr + displacement;
+                                       parser.findTargetFromAddressAndSectionNum(dstAddr, reloc->r_symbolnum(), target);
+                               }
+                               // special case "calls" for dtrace 
+                               if ( (target.name != NULL) && (strncmp(target.name, "___dtrace_probe$", 16) == 0) ) {
+                                       parser.addFixup(src, ld::Fixup::k1of1,
+                                                                                                                       ld::Fixup::kindStoreARMDtraceCallSiteNop, false, target.name);
+                                       parser.addDtraceExtraInfos(src, &target.name[16]);
+                               }
+                               else if ( (target.name != NULL) && (strncmp(target.name, "___dtrace_isenabled$", 20) == 0) ) {
+                                       parser.addFixup(src, ld::Fixup::k1of1, 
+                                                                                                                       ld::Fixup::kindStoreARMDtraceIsEnableSiteClear, false, target.name);
+                                       parser.addDtraceExtraInfos(src, &target.name[20]);
+                               }
+                               else {
+                                       parser.addFixups(src, ld::Fixup::kindStoreARMBranch24, target);
+                               }
+                               break;
+                       case ARM_THUMB_RELOC_BR22:
+                               // thumb2 added two more bits to displacement, complicating the displacement decoding
+                               {
+                                       uint32_t s = (instruction >> 10) & 0x1;
+                                       uint32_t j1 = (instruction >> 29) & 0x1;
+                                       uint32_t j2 = (instruction >> 27) & 0x1;
+                                       uint32_t imm10 = instruction & 0x3FF;
+                                       uint32_t imm11 = (instruction >> 16) & 0x7FF;
+                                       uint32_t i1 = (j1 == s);
+                                       uint32_t i2 = (j2 == s);
+                                       uint32_t dis = (s << 24) | (i1 << 23) | (i2 << 22) | (imm10 << 12) | (imm11 << 1);
+                                       int32_t sdis = dis;
+                                       if ( s )
+                                               sdis |= 0xFE000000;
+                                       displacement = sdis;
+                               }
+                               // The pc added will be +4 from the pc
+                               displacement += 4;
+                               // If the instruction was blx, force the low 2 bits to be clear
+                               dstAddr = srcAddr + displacement;
+                               if ((instruction & 0xF8000000) == 0xE8000000)
+                                       dstAddr &= 0xFFFFFFFC;
+
+                               if ( reloc->r_extern() ) {
+                                       target.addend = dstAddr;
+                               }
+                               else {
+                                       parser.findTargetFromAddressAndSectionNum(dstAddr, reloc->r_symbolnum(), target);
+                               }
+                               // special case "calls" for dtrace 
+                               if ( (target.name != NULL) && (strncmp(target.name, "___dtrace_probe$", 16) == 0) ) {
+                                       parser.addFixup(src, ld::Fixup::k1of1,
+                                                                                                                       ld::Fixup::kindStoreThumbDtraceCallSiteNop, false, target.name);
+                                       parser.addDtraceExtraInfos(src, &target.name[16]);
+                               }
+                               else if ( (target.name != NULL) && (strncmp(target.name, "___dtrace_isenabled$", 20) == 0) ) {
+                                       parser.addFixup(src, ld::Fixup::k1of1, 
+                                                                                                                       ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear, false, target.name);
+                                       parser.addDtraceExtraInfos(src, &target.name[20]);
+                               }
+                               else {
+                                       parser.addFixups(src, ld::Fixup::kindStoreThumbBranch22, target);
+                               }
+                               break;
+                       case ARM_RELOC_VANILLA:
+                               if ( reloc->r_length() != 2 )
+                                       throw "bad length for ARM_RELOC_VANILLA";
+                               contentValue = LittleEndian::get32(*fixUpPtr);
+                               if ( reloc->r_extern() ) {
+                                       target.addend = contentValue;
+                                       if ( externSymbolIsThumbDef )
+                                               target.addend &= -2; // remove thumb bit
+                               }
+                               else {
+                                       parser.findTargetFromAddressAndSectionNum(contentValue, reloc->r_symbolnum(), target);
+                                       // possible non-extern relocation turned into by-name ref because target is a weak-def
+                                       if ( target.atom != NULL ) {
+                                               if ( target.atom->isThumb() )
+                                                       target.addend &= -2; // remove thumb bit
+                                               // if reference to LSDA, add group subordinate fixup
+                                               if ( target.atom->contentType() == ld::Atom::typeLSDA ) {
+                                                       Parser<arm>::SourceLocation     src2;
+                                                       src2.atom = src.atom;
+                                                       src2.offsetInAtom = 0;
+                                                       parser.addFixup(src2, ld::Fixup::k1of1, ld::Fixup::kindNoneGroupSubordinateLSDA, target.atom);
+                                               }
+                                       }
+                               }
+                               parser.addFixups(src, ld::Fixup::kindStoreLittleEndian32, target);
+                               break;
+                       case ARM_THUMB_32BIT_BRANCH:
+                               // silently ignore old unnecessary reloc
+                               break;
+                       case ARM_RELOC_HALF:
+                               nextReloc = &reloc[1];
+                               if ( nextReloc->r_type() == ARM_RELOC_PAIR ) {
+                                       uint32_t instruction16;
+                                       uint32_t other16 = (nextReloc->r_address() & 0xFFFF);
+                                       bool isThumb;
+                                       if ( reloc->r_length() & 2 ) {
+                                               isThumb = true;
+                                               uint32_t i =    ((instruction & 0x00000400) >> 10);
+                                               uint32_t imm4 =  (instruction & 0x0000000F);
+                                               uint32_t imm3 = ((instruction & 0x70000000) >> 28);
+                                               uint32_t imm8 = ((instruction & 0x00FF0000) >> 16);
+                                               instruction16 = (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8;
+                                       }
+                                       else {
+                                               isThumb = false;
+                                               uint32_t imm4 = ((instruction & 0x000F0000) >> 16);
+                                               uint32_t imm12 = (instruction & 0x00000FFF);
+                                               instruction16 = (imm4 << 12) | imm12;
+                                       }
+                                       if ( reloc->r_length() & 1 ) {
+                                               // high 16
+                                               dstAddr = ((instruction16 << 16) | other16);
+                                               parser.findTargetFromAddress(dstAddr, target);
+                                               parser.addFixups(src, (isThumb ? ld::Fixup::kindStoreThumbHigh16 : ld::Fixup::kindStoreARMHigh16), target);
+                                       }
+                                       else {
+                                               // low 16
+                                               dstAddr = (other16 << 16) | instruction16;
+                                               parser.findTargetFromAddress(dstAddr, target);
+                                               parser.addFixups(src, (isThumb ? ld::Fixup::kindStoreThumbLow16 : ld::Fixup::kindStoreARMLow16), target);
+                                       }
+                                       result = true;
+                               }
+                               else
+                                       throw "for ARM_RELOC_HALF, next reloc is not ARM_RELOC_PAIR";
+                               break;
+                       default:
+                               throwf("unknown relocation type %d", reloc->r_type());
+                               break;
+               }
+       }
+       else {
+               const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
+               // file format allows pair to be scattered or not
+               const macho_scattered_relocation_info<P>* nextSReloc = &sreloc[1];
+               nextReloc = &reloc[1];
+               srcAddr = sect->addr() + sreloc->r_address();
+               dstAddr = sreloc->r_value();
+               fixUpPtr = (uint32_t*)(file().fileContent() + sect->offset() + sreloc->r_address());
+               instruction = LittleEndian::get32(*fixUpPtr);
+               src.atom = this->findAtomByAddress(srcAddr);
+               src.offsetInAtom = srcAddr - src.atom->_objAddress;
+               bool nextRelocIsPair = false;
+               uint32_t nextRelocAddress = 0;
+               uint32_t nextRelocValue = 0;
+               if ( (nextReloc->r_address() & R_SCATTERED) == 0 ) {
+                       if ( nextReloc->r_type() == ARM_RELOC_PAIR ) {
+                               nextRelocIsPair = true;
+                               nextRelocAddress = nextReloc->r_address();
+                               result = true;
+                       }
+               }
+               else {
+                       if ( nextSReloc->r_type() == ARM_RELOC_PAIR ) {
+                               nextRelocIsPair = true;
+                               nextRelocAddress = nextSReloc->r_address();
+                               nextRelocValue = nextSReloc->r_value();
+                               result = true;
+                       }
+               }
+               switch ( sreloc->r_type() ) {
+                       case ARM_RELOC_VANILLA:
+                               // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr)
+                               if ( sreloc->r_length() != 2 )
+                                       throw "bad length for ARM_RELOC_VANILLA";
+                               target.atom = parser.findAtomByAddress(sreloc->r_value());
+                               contentValue = LittleEndian::get32(*fixUpPtr);
+                               target.addend = contentValue - target.atom->_objAddress;
+                               if ( target.atom->isThumb() )
+                                       target.addend &= -2; // remove thumb bit
+                               parser.addFixups(src, ld::Fixup::kindStoreLittleEndian32, target);
+                               break;
+                       case ARM_RELOC_BR24:
+                               // Sign-extend displacement
+                               displacement = (instruction & 0x00FFFFFF) << 2;
+                               if ( (displacement & 0x02000000) != 0 )
+                                       displacement |= 0xFC000000;
+                               // The pc added will be +8 from the pc
+                               displacement += 8;
+                               // If this is BLX add H << 1
+                               if ((instruction & 0xFE000000) == 0xFA000000)
+                                       displacement += ((instruction & 0x01000000) >> 23);
+                               target.atom = parser.findAtomByAddress(sreloc->r_value());
+                               target.addend = (int64_t)(srcAddr + displacement) - (int64_t)(target.atom->_objAddress);
+                               parser.addFixups(src, ld::Fixup::kindStoreARMBranch24, target);
+                               break;
+                       case ARM_THUMB_RELOC_BR22:
+                               // thumb2 added two more bits to displacement, complicating the displacement decoding
+                               {
+                                       uint32_t s = (instruction >> 10) & 0x1;
+                                       uint32_t j1 = (instruction >> 29) & 0x1;
+                                       uint32_t j2 = (instruction >> 27) & 0x1;
+                                       uint32_t imm10 = instruction & 0x3FF;
+                                       uint32_t imm11 = (instruction >> 16) & 0x7FF;
+                                       uint32_t i1 = (j1 == s);
+                                       uint32_t i2 = (j2 == s);
+                                       uint32_t dis = (s << 24) | (i1 << 23) | (i2 << 22) | (imm10 << 12) | (imm11 << 1);
+                                       int32_t sdis = dis;
+                                       if ( s )
+                                               sdis |= 0xFE000000;
+                                       displacement = sdis;
+                               }
+                               // The pc added will be +4 from the pc
+                               displacement += 4;
+                               dstAddr = srcAddr+displacement;
+                               // If the instruction was blx, force the low 2 bits to be clear
+                               if ((instruction & 0xF8000000) == 0xE8000000)
+                                       dstAddr &= 0xFFFFFFFC;
+                               target.atom = parser.findAtomByAddress(sreloc->r_value());
+                               target.addend = dstAddr - target.atom->_objAddress;
+                               parser.addFixups(src, ld::Fixup::kindStoreThumbBranch22, target);
+                               break;
+                       case ARM_RELOC_SECTDIFF:
+                       case ARM_RELOC_LOCAL_SECTDIFF:
+                               {
+                                       if ( ! nextRelocIsPair ) 
+                                               throw "ARM_RELOC_SECTDIFF missing following pair";
+                                       if ( sreloc->r_length() != 2 )
+                                               throw "bad length for ARM_RELOC_SECTDIFF";
+                                       contentValue = LittleEndian::get32(*fixUpPtr);
+                                       Atom<arm>* fromAtom  = parser.findAtomByAddress(nextRelocValue);
+                                       uint32_t offsetInFrom = nextRelocValue - fromAtom->_objAddress;
+                                       uint32_t offsetInTarget;
+                                       Atom<arm>* targetAtom = parser.findAtomByAddressOrLocalTargetOfStub(sreloc->r_value(), &offsetInTarget);
+                                       // check for addend encoded in the section content
+                    int64_t addend = contentValue - (sreloc->r_value() - nextRelocValue);
+                                       if ( targetAtom->isThumb() )
+                                               addend &= -2; // remove thumb bit
+                                       // if reference to LSDA, add group subordinate fixup
+                                       if ( targetAtom->contentType() == ld::Atom::typeLSDA ) {
+                                               Parser<arm>::SourceLocation     src2;
+                                               src2.atom = src.atom;
+                                               src2.offsetInAtom = 0;
+                                               parser.addFixup(src2, ld::Fixup::k1of1, ld::Fixup::kindNoneGroupSubordinateLSDA, targetAtom);
+                                       }
+                                       if ( addend < 0 ) { 
+                                               // switch binding base on coalescing
+                                               if ( targetAtom->scope() == ld::Atom::scopeTranslationUnit ) {
+                                                       parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, targetAtom);
+                                               }
+                                               else if ( (targetAtom->combine() == ld::Atom::combineByNameAndContent) || (targetAtom->combine() == ld::Atom::combineByNameAndReferences) ) {
+                                                       parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, ld::Fixup::bindingByContentBound, targetAtom);
+                                               }
+                                               else {
+                                                       parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, false, targetAtom->name());
+                                               }
+                                               parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, targetAtom);
+                                               parser.addFixup(src, ld::Fixup::k2of5, ld::Fixup::kindAddAddend, offsetInTarget);
+                                               parser.addFixup(src, ld::Fixup::k3of5, ld::Fixup::kindSubtractTargetAddress, fromAtom);
+                                               parser.addFixup(src, ld::Fixup::k4of5, ld::Fixup::kindSubtractAddend, offsetInFrom-addend);
+                                               parser.addFixup(src, ld::Fixup::k5of5, ld::Fixup::kindStoreLittleEndian32);
+                                       }
+                                       else {
+                                               if ( targetAtom->scope() == ld::Atom::scopeTranslationUnit ) {
+                                                       parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, targetAtom);
+                                               }
+                                               else if ( (targetAtom->combine() == ld::Atom::combineByNameAndContent) || (targetAtom->combine() == ld::Atom::combineByNameAndReferences) ) {
+                                                       parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, ld::Fixup::bindingByContentBound, targetAtom);
+                                               }
+                                               else {
+                                                       parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, false, targetAtom->name());
+                                               }
+                                               parser.addFixup(src, ld::Fixup::k2of5, ld::Fixup::kindAddAddend, (uint32_t)(offsetInTarget+addend));
+                                               parser.addFixup(src, ld::Fixup::k3of5, ld::Fixup::kindSubtractTargetAddress, fromAtom);
+                                               parser.addFixup(src, ld::Fixup::k4of5, ld::Fixup::kindSubtractAddend, offsetInFrom);
+                                               parser.addFixup(src, ld::Fixup::k5of5, ld::Fixup::kindStoreLittleEndian32);
+                                       }
+                               }
+                               break;
+                       case ARM_RELOC_HALF_SECTDIFF:
+                               if ( nextRelocIsPair ) {
+                                       instruction = LittleEndian::get32(*fixUpPtr);
+                                       Atom<arm>* fromAtom  = parser.findAtomByAddress(nextRelocValue);
+                                       uint32_t offsetInFrom = nextRelocValue - fromAtom->_objAddress;
+                                       Atom<arm>* targetAtom  = parser.findAtomByAddress(sreloc->r_value());
+                                       uint32_t offsetInTarget = sreloc->r_value() - targetAtom->_objAddress;
+                                       //if ( targetAtom->isThumb() )
+                                       //      addend &= -2; // remove thumb bit
+                                       uint32_t instruction16;
+                                       uint32_t other16 = (nextRelocAddress & 0xFFFF);
+                                       bool isThumb;
+                                       if ( sreloc->r_length() & 2 ) {
+                                               isThumb = true;
+                                               uint32_t i =    ((instruction & 0x00000400) >> 10);
+                                               uint32_t imm4 =  (instruction & 0x0000000F);
+                                               uint32_t imm3 = ((instruction & 0x70000000) >> 28);
+                                               uint32_t imm8 = ((instruction & 0x00FF0000) >> 16);
+                                               instruction16 = (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8;
+                                       }
+                                       else {
+                                               isThumb = false;
+                                               uint32_t imm4 = ((instruction & 0x000F0000) >> 16);
+                                               uint32_t imm12 = (instruction & 0x00000FFF);
+                                               instruction16 = (imm4 << 12) | imm12;
+                                       }
+                                       if ( sreloc->r_length() & 1 )
+                                               dstAddr = ((instruction16 << 16) | other16);
+                                       else 
+                                               dstAddr = (other16 << 16) | instruction16;
+                    int32_t addend = dstAddr - (sreloc->r_value() - nextRelocValue);
+                                       if ( targetAtom->scope() == ld::Atom::scopeTranslationUnit ) {
+                                               parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, targetAtom);
+                                       }
+                                       else if ( (targetAtom->combine() == ld::Atom::combineByNameAndContent) || (targetAtom->combine() == ld::Atom::combineByNameAndReferences) ) {
+                                               parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, ld::Fixup::bindingByContentBound, targetAtom);
+                                       }
+                                       else {
+                                               parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, false, targetAtom->name());
+                                       }
+                                       parser.addFixup(src, ld::Fixup::k2of5, ld::Fixup::kindAddAddend, (uint32_t)offsetInTarget+addend);
+                                       parser.addFixup(src, ld::Fixup::k3of5, ld::Fixup::kindSubtractTargetAddress, fromAtom);
+                                       parser.addFixup(src, ld::Fixup::k4of5, ld::Fixup::kindSubtractAddend, offsetInFrom);
+                                       if ( sreloc->r_length() & 1 ) {
+                                               // high 16
+                                               parser.addFixup(src, ld::Fixup::k5of5, (isThumb ? ld::Fixup::kindStoreThumbHigh16 : ld::Fixup::kindStoreARMHigh16));
+                                       }
+                                       else {
+                                               // low 16
+                                               parser.addFixup(src, ld::Fixup::k5of5, (isThumb ? ld::Fixup::kindStoreThumbLow16 : ld::Fixup::kindStoreARMLow16));
+                                       }
+                                       result = true;
+                               }
+                               else
+                                       throw "ARM_RELOC_HALF_SECTDIFF reloc missing following pair";
+                               break;
+                       case ARM_RELOC_HALF:
+                               if ( nextRelocIsPair ) {
+                                       instruction = LittleEndian::get32(*fixUpPtr);
+                                       Atom<arm>* targetAtom  = parser.findAtomByAddress(sreloc->r_value());
+                                       uint32_t instruction16;
+                                       uint32_t other16 = (nextRelocAddress & 0xFFFF);
+                                       bool isThumb;
+                                       if ( sreloc->r_length() & 2 ) {
+                                               isThumb = true;
+                                               uint32_t i =    ((instruction & 0x00000400) >> 10);
+                                               uint32_t imm4 =  (instruction & 0x0000000F);
+                                               uint32_t imm3 = ((instruction & 0x70000000) >> 28);
+                                               uint32_t imm8 = ((instruction & 0x00FF0000) >> 16);
+                                               instruction16 = (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8;
+                                       }
+                                       else {
+                                               isThumb = false;
+                                               uint32_t imm4 = ((instruction & 0x000F0000) >> 16);
+                                               uint32_t imm12 = (instruction & 0x00000FFF);
+                                               instruction16 = (imm4 << 12) | imm12;
+                                       }
+                                       if ( sreloc->r_length() & 1 )
+                                               dstAddr = ((instruction16 << 16) | other16);
+                                       else 
+                                               dstAddr = (other16 << 16) | instruction16;
+                                       if ( targetAtom->scope() == ld::Atom::scopeTranslationUnit ) {
+                                               parser.addFixup(src, ld::Fixup::k1of3, ld::Fixup::kindSetTargetAddress, targetAtom);
+                                       }
+                                       else if ( (targetAtom->combine() == ld::Atom::combineByNameAndContent) || (targetAtom->combine() == ld::Atom::combineByNameAndReferences) ) {
+                                               parser.addFixup(src, ld::Fixup::k1of3, ld::Fixup::kindSetTargetAddress, ld::Fixup::bindingByContentBound, targetAtom);
+                                       }
+                                       else {
+                                               parser.addFixup(src, ld::Fixup::k1of3, ld::Fixup::kindSetTargetAddress, false, targetAtom->name());
+                                       }
+                                       parser.addFixup(src, ld::Fixup::k2of3, ld::Fixup::kindAddAddend, dstAddr - targetAtom->_objAddress);
+                                       if ( sreloc->r_length() & 1 ) {
+                                               // high 16
+                                               parser.addFixup(src, ld::Fixup::k3of3, (isThumb ? ld::Fixup::kindStoreThumbHigh16 : ld::Fixup::kindStoreARMHigh16));
+                                       }
+                                       else {
+                                               // low 16
+                                               parser.addFixup(src, ld::Fixup::k3of3, (isThumb ? ld::Fixup::kindStoreThumbLow16 : ld::Fixup::kindStoreARMLow16));
+                                       }
+                                       result = true;
+                               }
+                               else
+                                       throw "scattered ARM_RELOC_HALF reloc missing following pair";
+                               break;
+                       default:
+                               throwf("unknown ARM scattered relocation type %d", sreloc->r_type());
+               }
+       }
+       return result;
+}
+
+
+
+
+
+template <typename A>
+bool ObjC1ClassSection<A>::addRelocFixup(class Parser<A>& parser, const macho_relocation_info<P>* reloc)
+{
+       // inherited
+       FixedSizeSection<A>::addRelocFixup(parser, reloc);
+       
+       assert(0 && "needs template specialization");
+       return false;
+}
+
+template <>
+bool ObjC1ClassSection<x86>::addRelocFixup(class Parser<x86>& parser, const macho_relocation_info<x86::P>* reloc)
+{
+       // if this is the reloc for the super class name string, add implicit reference to super class
+       if ( ((reloc->r_address() & R_SCATTERED) == 0) && (reloc->r_type() == GENERIC_RELOC_VANILLA) ) {
+               assert( reloc->r_length() == 2 );
+               assert( ! reloc->r_pcrel() );
+               
+               const macho_section<P>* sect = this->machoSection();
+               Parser<x86>::SourceLocation     src;
+               uint32_t srcAddr = sect->addr() + reloc->r_address();
+               src.atom = this->findAtomByAddress(srcAddr);
+               src.offsetInAtom = srcAddr - src.atom->objectAddress();
+               if ( src.offsetInAtom == 4 ) {
+                       Parser<x86>::TargetDesc         stringTarget;
+                       const uint8_t* fixUpPtr = file().fileContent() + sect->offset() + reloc->r_address();
+                       uint32_t contentValue = LittleEndian::get32(*((uint32_t*)fixUpPtr));
+                       parser.findTargetFromAddressAndSectionNum(contentValue, reloc->r_symbolnum(), stringTarget);
+                       
+                       assert(stringTarget.atom != NULL);
+                       assert(stringTarget.atom->contentType() == ld::Atom::typeCString);
+                       const char* superClassBaseName = (char*)stringTarget.atom->rawContentPointer();
+                       char* superClassName = new char[strlen(superClassBaseName) + 20];
+                       strcpy(superClassName, ".objc_class_name_");
+                       strcat(superClassName, superClassBaseName);
+                       
+                       parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindSetTargetAddress, false, superClassName);
+               }
+       }
+       // inherited
+       return FixedSizeSection<x86>::addRelocFixup(parser, reloc);
+}
+
+template <>
+bool ObjC1ClassSection<ppc>::addRelocFixup(class Parser<ppc>& parser, const macho_relocation_info<ppc::P>* reloc)
+{
+       // if this is the reloc for the super class name string, add implicit reference to super class
+       if ( ((reloc->r_address() & R_SCATTERED) == 0) && (reloc->r_type() == PPC_RELOC_VANILLA) ) {
+               assert( reloc->r_length() == 2 );
+               assert( ! reloc->r_pcrel() );
+       
+               const macho_section<P>* sect = this->machoSection();
+               Parser<ppc>::SourceLocation     src;
+               uint32_t srcAddr = sect->addr() + reloc->r_address();
+               src.atom = this->findAtomByAddress(srcAddr);
+               src.offsetInAtom = srcAddr - src.atom->objectAddress();
+               if ( src.offsetInAtom == 4 ) {
+                       Parser<ppc>::TargetDesc         stringTarget;
+                       const uint8_t* fixUpPtr = file().fileContent() + sect->offset() + reloc->r_address();
+                       uint32_t contentValue = BigEndian::get32(*((uint32_t*)fixUpPtr));
+                       parser.findTargetFromAddressAndSectionNum(contentValue, reloc->r_symbolnum(), stringTarget);
+                       
+                       assert(stringTarget.atom != NULL);
+                       assert(stringTarget.atom->contentType() == ld::Atom::typeCString);
+                       const char* superClassBaseName = (char*)stringTarget.atom->rawContentPointer();
+                       char* superClassName = new char[strlen(superClassBaseName) + 20];
+                       strcpy(superClassName, ".objc_class_name_");
+                       strcat(superClassName, superClassBaseName);
+                       
+                       parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindSetTargetAddress, false, superClassName);
+               }
+       }
+       
+       // inherited
+       return FixedSizeSection<ppc>::addRelocFixup(parser, reloc);
+}
+
+
+
+
+template <typename A>
+bool Objc1ClassReferences<A>::addRelocFixup(class Parser<A>& parser, const macho_relocation_info<P>* reloc)
+{
+       // inherited
+       PointerToCStringSection<A>::addRelocFixup(parser, reloc);
+       
+       assert(0 && "needs template specialization");
+       return false;
+}
+
+
+template <>
+bool Objc1ClassReferences<ppc>::addRelocFixup(class Parser<ppc>& parser, const macho_relocation_info<ppc::P>* reloc)
+{
+       // add implict class refs, fixups not usable yet, so look at relocations
+       assert( (reloc->r_address() & R_SCATTERED) == 0 );
+       assert( reloc->r_type() == PPC_RELOC_VANILLA );
+       assert( reloc->r_length() == 2 );
+       assert( ! reloc->r_pcrel() );
+       
+       const macho_section<P>* sect = this->machoSection();
+       Parser<ppc>::SourceLocation     src;
+       uint32_t srcAddr = sect->addr() + reloc->r_address();
+       src.atom = this->findAtomByAddress(srcAddr);
+       src.offsetInAtom = srcAddr - src.atom->objectAddress();
+       Parser<ppc>::TargetDesc         stringTarget;
+       const uint8_t* fixUpPtr = file().fileContent() + sect->offset() + reloc->r_address();
+       uint32_t contentValue = BigEndian::get32(*((uint32_t*)fixUpPtr));
+       parser.findTargetFromAddressAndSectionNum(contentValue, reloc->r_symbolnum(), stringTarget);
+       
+       assert(stringTarget.atom != NULL);
+       assert(stringTarget.atom->contentType() == ld::Atom::typeCString);
+       const char* baseClassName = (char*)stringTarget.atom->rawContentPointer();
+       char* objcClassName = new char[strlen(baseClassName) + 20];
+       strcpy(objcClassName, ".objc_class_name_");
+       strcat(objcClassName, baseClassName);
+
+       parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindSetTargetAddress, false, objcClassName);
+
+       // inherited
+       return PointerToCStringSection<ppc>::addRelocFixup(parser, reloc);
+}
+
+
+template <>
+bool Objc1ClassReferences<x86>::addRelocFixup(class Parser<x86>& parser, const macho_relocation_info<x86::P>* reloc)
+{
+       // add implict class refs, fixups not usable yet, so look at relocations
+       assert( (reloc->r_address() & R_SCATTERED) == 0 );
+       assert( reloc->r_type() == GENERIC_RELOC_VANILLA );
+       assert( reloc->r_length() == 2 );
+       assert( ! reloc->r_pcrel() );
+       
+       const macho_section<P>* sect = this->machoSection();
+       Parser<x86>::SourceLocation     src;
+       uint32_t srcAddr = sect->addr() + reloc->r_address();
+       src.atom = this->findAtomByAddress(srcAddr);
+       src.offsetInAtom = srcAddr - src.atom->objectAddress();
+       Parser<x86>::TargetDesc         stringTarget;
+       const uint8_t* fixUpPtr = file().fileContent() + sect->offset() + reloc->r_address();
+       uint32_t contentValue = LittleEndian::get32(*((uint32_t*)fixUpPtr));
+       parser.findTargetFromAddressAndSectionNum(contentValue, reloc->r_symbolnum(), stringTarget);
+       
+       assert(stringTarget.atom != NULL);
+       assert(stringTarget.atom->contentType() == ld::Atom::typeCString);
+       const char* baseClassName = (char*)stringTarget.atom->rawContentPointer();
+       char* objcClassName = new char[strlen(baseClassName) + 20];
+       strcpy(objcClassName, ".objc_class_name_");
+       strcat(objcClassName, baseClassName);
+
+       parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindSetTargetAddress, false, objcClassName);
+
+       // inherited
+       return PointerToCStringSection<x86>::addRelocFixup(parser, reloc);
+}
+
+
+template <typename A>
+void Section<A>::makeFixups(class Parser<A>& parser, const struct Parser<A>::CFIInfoArray&)
+{
+       const macho_section<P>* sect = this->machoSection();
+       const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)(file().fileContent() + sect->reloff());
+       const uint32_t relocCount = sect->nreloc();
+       for (uint32_t r = 0; r < relocCount; ++r) {
+               try {
+                       if ( this->addRelocFixup(parser, &relocs[r]) )
+                               ++r; // skip next
+               }
+               catch (const char* msg) {
+                       throwf("in section %s,%s reloc %u: %s", sect->segname(), sect->sectname(), r, msg);
+               }
+       }
+       
+       // add follow-on fixups if .o file is missing .subsections_via_symbols
+       if ( this->addFollowOnFixups() ) {
+               Atom<A>* end = &_endAtoms[-1];
+               for(Atom<A>* p = _beginAtoms; p < end; ++p) {
+                       typename Parser<A>::SourceLocation src(p, 0);
+                       Atom<A>* nextAtom = &p[1];
+                       parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindNoneFollowOn, nextAtom);
+               }
+       }
+       else if ( this->type() == ld::Section::typeCode ) {
+               // if FDE broke text not at a symbol, use followOn to keep code together
+               Atom<A>* end = &_endAtoms[-1];
+               for(Atom<A>* p = _beginAtoms; p < end; ++p) {
+                       typename Parser<A>::SourceLocation src(p, 0);
+                       Atom<A>* nextAtom = &p[1];
+                       if ( (p->symbolTableInclusion() == ld::Atom::symbolTableIn) && (nextAtom->symbolTableInclusion() == ld::Atom::symbolTableNotIn) ) {
+                               parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindNoneFollowOn, nextAtom);
+                       }
+               }
+       }
+       
+       // add follow-on fixups for aliases
+       if ( _hasAliases ) {
+               for(Atom<A>* p = _beginAtoms; p < _endAtoms; ++p) {
+                       if ( p->isAlias() && ! this->addFollowOnFixups() ) {
+                               Atom<A>* targetOfAlias = &p[1];
+                               assert(p < &_endAtoms[-1]);
+                               assert(p->_objAddress == targetOfAlias->_objAddress);
+                               typename Parser<A>::SourceLocation src(p, 0);
+                               parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindNoneFollowOn, targetOfAlias);
+                       }
+               }
+       }
+}
+
+
+
+//
+// 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)
+{
+       switch ( opts.architecture ) {
+               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;
+               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;
+               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;
+               case CPU_TYPE_POWERPC:
+                       if ( mach_o::relocatable::Parser<ppc>::validFile(fileContent) )
+                               return mach_o::relocatable::Parser<ppc>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
+                       break;
+               case CPU_TYPE_POWERPC64:
+                       if ( mach_o::relocatable::Parser<ppc64>::validFile(fileContent) )
+                               return mach_o::relocatable::Parser<ppc64>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
+                       break;
+       }
+       return NULL;
+}
+
+//
+// used by archive reader to validate member object file
+//
+bool isObjectFile(const uint8_t* fileContent, uint64_t fileLength, const ParserOptions& opts)
+{
+       switch ( opts.architecture ) {
+               case CPU_TYPE_X86_64:
+                       return ( mach_o::relocatable::Parser<x86_64>::validFile(fileContent) );
+               case CPU_TYPE_I386:
+                       return ( mach_o::relocatable::Parser<x86>::validFile(fileContent) );
+               case CPU_TYPE_ARM:
+                       return ( mach_o::relocatable::Parser<arm>::validFile(fileContent, opts.objSubtypeMustMatch, opts.subType) );
+               case CPU_TYPE_POWERPC:
+                       return ( mach_o::relocatable::Parser<ppc>::validFile(fileContent) );
+               case CPU_TYPE_POWERPC64:
+                       return ( mach_o::relocatable::Parser<ppc64>::validFile(fileContent) );
+       }
+       return false;
+}
+
+//
+// used by linker to infer architecture when no -arch is on command line
+//
+bool isObjectFile(const uint8_t* fileContent, cpu_type_t* result, cpu_subtype_t* subResult)
+{
+       if ( mach_o::relocatable::Parser<x86_64>::validFile(fileContent) ) {
+               *result = CPU_TYPE_X86_64;
+               *subResult = CPU_SUBTYPE_X86_64_ALL;
+               return true;
+       }
+       if ( mach_o::relocatable::Parser<x86>::validFile(fileContent) ) {
+               *result = CPU_TYPE_I386;
+               *subResult = CPU_SUBTYPE_X86_ALL;
+               return true;
+       }
+       if ( mach_o::relocatable::Parser<arm>::validFile(fileContent, false, 0) ) {
+               *result = CPU_TYPE_ARM;
+               const macho_header<Pointer32<LittleEndian> >* header = (const macho_header<Pointer32<LittleEndian> >*)fileContent;
+               *subResult = header->cpusubtype();
+               return true;
+       }
+       if ( mach_o::relocatable::Parser<ppc>::validFile(fileContent) ) {
+               *result = CPU_TYPE_POWERPC;
+               const macho_header<Pointer32<BigEndian> >* header = (const macho_header<Pointer32<BigEndian> >*)fileContent;
+               *subResult = header->cpusubtype();
+               return true;
+       }
+       if ( mach_o::relocatable::Parser<ppc64>::validFile(fileContent) ) {
+               *result = CPU_TYPE_POWERPC64;
+               *subResult = CPU_SUBTYPE_POWERPC_ALL;
+               return true;
+       }
+       return false;
+}                                      
+
+//
+// used by linker is error messages to describe bad .o file
+//
+const char* archName(const uint8_t* fileContent)
+{
+       if ( mach_o::relocatable::Parser<x86_64>::validFile(fileContent) ) {
+               return mach_o::relocatable::Parser<x86_64>::fileKind(fileContent);
+       }
+       if ( mach_o::relocatable::Parser<x86>::validFile(fileContent) ) {
+               return mach_o::relocatable::Parser<x86>::fileKind(fileContent);
+       }
+       if ( mach_o::relocatable::Parser<arm>::validFile(fileContent, false, 0) ) {
+               return mach_o::relocatable::Parser<arm>::fileKind(fileContent);
+       }
+       if ( mach_o::relocatable::Parser<ppc>::validFile(fileContent) ) {
+               return mach_o::relocatable::Parser<ppc>::fileKind(fileContent);
+       }
+       if ( mach_o::relocatable::Parser<ppc64>::validFile(fileContent) ) {
+               return mach_o::relocatable::Parser<ppc64>::fileKind(fileContent);
+       }
+       return NULL;
+}
+
+//
+// Used by archive reader when -ObjC option is specified
+//     
+bool hasObjC2Categories(const uint8_t* fileContent)
+{
+       if ( mach_o::relocatable::Parser<x86_64>::validFile(fileContent) ) {
+               return mach_o::relocatable::Parser<x86_64>::hasObjC2Categories(fileContent);
+       }
+       else if ( mach_o::relocatable::Parser<arm>::validFile(fileContent, false, 0) ) {
+               return mach_o::relocatable::Parser<arm>::hasObjC2Categories(fileContent);
+       }
+       return false;
+}                              
+
+
+
+} // namespace relocatable
+} // namespace mach_o
+
+
diff --git a/src/ld/parsers/macho_relocatable_file.h b/src/ld/parsers/macho_relocatable_file.h
new file mode 100644 (file)
index 0000000..6d0e25e
--- /dev/null
@@ -0,0 +1,58 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2009-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@
+ */
+
+#ifndef __MACHO_RELOCATABLE_FILE_H__
+#define __MACHO_RELOCATABLE_FILE_H__
+
+#include "ld.hpp"
+#include "Options.h"
+
+namespace mach_o {
+namespace relocatable {
+
+struct ParserOptions {
+       uint32_t                architecture;
+       bool                    objSubtypeMustMatch;
+       bool                    logAllFiles;
+       bool                    convertUnwindInfo;
+       uint32_t                subType;
+};
+
+extern ld::relocatable::File* parse(const uint8_t* fileContent, uint64_t fileLength, 
+                                                                       const char* path, time_t modTime, uint32_t ordinal, 
+                                                                       const ParserOptions& opts);
+                                                                       
+extern bool isObjectFile(const uint8_t* fileContent, uint64_t fileLength, const ParserOptions& opts);
+
+extern bool isObjectFile(const uint8_t* fileContent, cpu_type_t* result, cpu_subtype_t* subResult);                                    
+
+extern bool hasObjC2Categories(const uint8_t* fileContent);                                    
+
+extern const char* archName(const uint8_t* fileContent);                                       
+
+} // namespace relocatable
+} // namespace mach_o
+
+
+#endif // __MACHO_RELOCATABLE_FILE_H__
diff --git a/src/ld/parsers/opaque_section_file.cpp b/src/ld/parsers/opaque_section_file.cpp
new file mode 100644 (file)
index 0000000..660f66d
--- /dev/null
@@ -0,0 +1,106 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <vector>
+
+#include "ld.hpp"
+#include "opaque_section_file.h"
+
+
+namespace opaque_section {
+
+
+
+class Atom : public ld::Atom {
+public:
+       virtual ld::File*                                               file() const                                    { return (ld::File*)&_file; }
+       virtual bool                                                    translationUnitSource(const char** dir, const char** ) const 
+                                                                                                                                                       { return false; }
+       virtual const char*                                             name() const                                    { return _name; }
+       virtual uint64_t                                                size() const                                    { return _size; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const
+                                                                                                                                                       { memcpy(buffer, _content, _size); }
+       virtual void                                                    setScope(Scope)                                 { }
+
+protected:
+       friend class File;
+                                                                                       Atom(class File& f, const char* n,  const uint8_t* content, uint64_t sz);
+       virtual                                                                 ~Atom() {}
+       
+       class File&                                                             _file;
+       const char*                                                             _name;
+       const uint8_t*                                                  _content;
+       uint64_t                                                                _size;
+};
+
+
+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 char* symbolName="sect_create")
+                                                                       : ld::File(pth, 0, ord),
+                                                                         _atom(*this, symbolName, fileContent, fileLength), 
+                                                                         _section(segmentName, sectionName, ld::Section::typeUnclassified) { }
+       virtual                                         ~File() { }
+       
+       virtual bool                            forEachAtom(ld::File::AtomHandler& h) const { h.doAtom(_atom); return true; }
+       virtual bool                            justInTimeforEachAtom(const char* name, ld::File::AtomHandler&) const { return false; }
+
+       ld::Atom*                                       atom() { return &_atom; }
+private:
+       friend class Atom;
+       
+       Atom                                            _atom;
+       ld::Section                                     _section;
+};
+
+Atom::Atom(File& f, const char* n,  const uint8_t* content, uint64_t sz)
+       : ld::Atom(f._section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+               ld::Atom::scopeTranslationUnit, ld::Atom::typeUnclassified, 
+               symbolTableNotIn, true, false, false, ld::Atom::Alignment(0)), 
+               _file(f), _name(n), _content(content), _size(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 char* symbolName)
+{
+       return new File(segmentName, sectionName, path, fileContent, fileLength, ordinal, symbolName);
+}
+
+
+} // namespace opaque_section
+
+
+
+
+
+
diff --git a/src/ld/parsers/opaque_section_file.h b/src/ld/parsers/opaque_section_file.h
new file mode 100644 (file)
index 0000000..04db805
--- /dev/null
@@ -0,0 +1,46 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __SECTION_FILE_H__
+#define __SECTION_FILE_H__
+
+
+
+#include "ld.hpp"
+
+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 char* symbolName="opaque_section");
+
+
+} // namespace opaque_section
+
+
+
+#endif // __SECTION_FILE_H__
+
+
+
diff --git a/src/ld/passes/branch_island.cpp b/src/ld/passes/branch_island.cpp
new file mode 100644 (file)
index 0000000..d42fa54
--- /dev/null
@@ -0,0 +1,623 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <stdint.h>
+#include <math.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <libkern/OSByteOrder.h>
+
+#include <vector>
+#include <map>
+
+#include "MachOFileAbstraction.hpp"
+#include "ld.hpp"
+#include "branch_island.h"
+
+namespace ld {
+namespace passes {
+namespace branch_island {
+
+
+
+
+struct TargetAndOffset { const ld::Atom* atom; uint32_t offset; };
+class TargetAndOffsetComparor
+{
+public:
+       bool operator()(const TargetAndOffset& left, const TargetAndOffset& right) const
+       {
+               if ( left.atom != right.atom )
+                       return ( left.atom < right.atom );
+               return ( left.offset < right.offset );
+       }
+};
+
+
+static bool _s_log = false;
+static ld::Section _s_text_section("__TEXT", "__text", ld::Section::typeCode);
+
+class PPCBranchIslandAtom : public ld::Atom {
+public:
+                                                                                       PPCBranchIslandAtom(const char* nm, const ld::Atom* target, TargetAndOffset finalTarget)
+                               : ld::Atom(_s_text_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeBranchIsland, 
+                                                       ld::Atom::symbolTableIn, false, false, false, ld::Atom::Alignment(2)), 
+                               _name(nm),
+                               _target(target),
+                               _finalTarget(finalTarget) { }
+
+       virtual const ld::File*                                 file() const                                    { return NULL; }
+       virtual bool                                                    translationUnitSource(const char** dir, const char**) const 
+                                                                                                                                                       { return false; }
+       virtual const char*                                             name() const                                    { return _name; }
+       virtual uint64_t                                                size() const                                    { return 4; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+               int64_t displacement = _target->finalAddress() - this->finalAddress();
+               const int64_t bl_sixteenMegLimit = 0x00FFFFFF;
+               if ( _target->contentType() == ld::Atom::typeBranchIsland ) {
+                       // try optimizing away intermediate islands
+                       int64_t skipToFinalDisplacement = _finalTarget.atom->finalAddress() + _finalTarget.offset - this->finalAddress();
+                       if ( (skipToFinalDisplacement > bl_sixteenMegLimit) && (skipToFinalDisplacement < (-bl_sixteenMegLimit)) ) {
+                               displacement = skipToFinalDisplacement;
+                       }
+               }
+               int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
+               OSWriteBigInt32(buffer, 0, branchInstruction);
+       }
+       virtual void                                                    setScope(Scope)                                 { }
+
+private:
+       const char*                                                             _name;
+       const ld::Atom*                                                 _target;
+       TargetAndOffset                                                 _finalTarget;
+};
+
+
+class ARMtoARMBranchIslandAtom : public ld::Atom {
+public:
+                                                                                       ARMtoARMBranchIslandAtom(const char* nm, const ld::Atom* target, TargetAndOffset finalTarget)
+                               : ld::Atom(_s_text_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeBranchIsland, 
+                                                       ld::Atom::symbolTableIn, false, false, false, ld::Atom::Alignment(2)), 
+                               _name(nm),
+                               _target(target),
+                               _finalTarget(finalTarget) { }
+
+       virtual const ld::File*                                 file() const                                    { return NULL; }
+       virtual bool                                                    translationUnitSource(const char** dir, const char**) const 
+                                                                                                                                                       { return false; }
+       virtual const char*                                             name() const                                    { return _name; }
+       virtual uint64_t                                                size() const                                    { return 4; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+               int64_t displacement = _target->finalAddress() - this->finalAddress() - 8;
+               if ( _target->contentType() == ld::Atom::typeBranchIsland ) {
+                       // an ARM branch can branch farther than a thumb branch.  The branch
+                       // island generation was conservative and put islands every thumb
+                       // branch distance apart.  Check to see if this is a an island
+                       // hopping branch that could be optimized to go directly to target.
+                       int64_t skipToFinalDisplacement = _finalTarget.atom->finalAddress() + _finalTarget.offset - this->finalAddress() - 8;
+                       if ( (skipToFinalDisplacement < 33554428LL) && (skipToFinalDisplacement > (-33554432LL)) ) {
+                               // can skip branch island and jump straight to target
+                               if (_s_log) fprintf(stderr, "%s: optimized jump to final target at 0x%08llX, thisAddr=0x%08llX\n", 
+                                                                                       _target->name(), _finalTarget.atom->finalAddress(), this->finalAddress());
+                               displacement = skipToFinalDisplacement;
+                       }
+                       else {
+                               // ultimate target is too far, jump to island
+                               if (_s_log) fprintf(stderr, "%s: jump to branch island at 0x%08llX\n", 
+                                                                                       _target->name(), _finalTarget.atom->finalAddress());
+                       }
+               }
+               uint32_t imm24 = (displacement >> 2) & 0x00FFFFFF;
+               int32_t branchInstruction = 0xEA000000 | imm24;
+               OSWriteLittleInt32(buffer, 0, branchInstruction);
+       }
+       virtual void                                                    setScope(Scope)                                 { }
+
+private:
+       const char*                                                             _name;
+       const ld::Atom*                                                 _target;
+       TargetAndOffset                                                 _finalTarget;
+};
+
+
+
+class ARMtoThumb1BranchIslandAtom : public ld::Atom {
+public:
+                                                                                       ARMtoThumb1BranchIslandAtom(const char* nm, const ld::Atom* target, TargetAndOffset finalTarget)
+                               : ld::Atom(_s_text_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeBranchIsland, 
+                                                       ld::Atom::symbolTableIn, false, false, false, ld::Atom::Alignment(2)), 
+                               _name(nm),
+                               _target(target),
+                               _finalTarget(finalTarget) { }
+
+       virtual const ld::File*                                 file() const                                    { return NULL; }
+       virtual bool                                                    translationUnitSource(const char** dir, const char**) 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 {
+               // There is no large displacement thumb1 branch instruction.
+               // Instead use ARM instructions that can jump to thumb.
+               // we use a 32-bit displacement, so we can directly jump to target which means no island hopping
+               int64_t displacement = _finalTarget.atom->finalAddress() + _finalTarget.offset - (this->finalAddress() + 12);
+               if ( _finalTarget.atom->isThumb() )
+                       displacement |= 1;
+               if (_s_log) fprintf(stderr, "%s: 4 ARM instruction jump to final target at 0x%08llX\n", 
+                                                                               _target->name(), _finalTarget.atom->finalAddress());
+               OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc004); //      ldr  ip, pc + 4
+               OSWriteLittleInt32(&buffer[ 4], 0, 0xe08fc00c); //      add      ip, pc, ip
+               OSWriteLittleInt32(&buffer[ 8], 0, 0xe12fff1c); //      bx       ip
+               OSWriteLittleInt32(&buffer[12], 0, displacement);       //      .long target-this               
+       }
+       virtual void                                                    setScope(Scope)                                 { }
+
+private:
+       const char*                                                             _name;
+       const ld::Atom*                                                 _target;
+       TargetAndOffset                                                 _finalTarget;
+};
+
+
+
+class Thumb2toThumbBranchIslandAtom : public ld::Atom {
+public:
+                                                                                       Thumb2toThumbBranchIslandAtom(const char* nm, const ld::Atom* target, TargetAndOffset finalTarget)
+                               : ld::Atom(_s_text_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeBranchIsland, 
+                                                       ld::Atom::symbolTableIn, false, true, false, ld::Atom::Alignment(1)), 
+                               _name(nm),
+                               _target(target),
+                               _finalTarget(finalTarget) { }
+
+       virtual const ld::File*                                 file() const                                    { return NULL; }
+       virtual bool                                                    translationUnitSource(const char** dir, const char**) const 
+                                                                                                                                                       { return false; }
+       virtual const char*                                             name() const                                    { return _name; }
+       virtual uint64_t                                                size() const                                    { return 4; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+               int64_t displacement = _target->finalAddress() - this->finalAddress() - 4;
+               if ( _target->contentType() == ld::Atom::typeBranchIsland ) {
+                       // an ARM branch can branch farther than a thumb branch.  The branch
+                       // island generation was conservative and put islands every thumb
+                       // branch distance apart.  Check to see if this is a an island
+                       // hopping branch that could be optimized to go directly to target.
+                       int64_t skipToFinalDisplacement = _finalTarget.atom->finalAddress() + _finalTarget.offset - this->finalAddress() - 4;
+                       if ( (skipToFinalDisplacement < 16777214) && (skipToFinalDisplacement > (-16777216LL)) ) {
+                               // can skip branch island and jump straight to target
+                               if (_s_log) fprintf(stderr, "%s: optimized jump to final target at 0x%08llX, thisAddr=0x%08llX\n", 
+                                                                                       _target->name(), _finalTarget.atom->finalAddress(), this->finalAddress());
+                               displacement = skipToFinalDisplacement;
+                       }
+                       else {
+                               // ultimate target is too far for thumb2 branch, jump to island
+                               if (_s_log) fprintf(stderr, "%s: jump to branch island at 0x%08llX\n", 
+                                                                                       _target->name(), _finalTarget.atom->finalAddress());
+                       }
+               }
+               // The instruction is really two instructions:
+               // The lower 16 bits are the first instruction, which contains the high
+               //   11 bits of the displacement.
+               // The upper 16 bits are the second instruction, which contains the low
+               //   11 bits of the displacement, as well as differentiating bl and blx.
+               uint32_t s = (uint32_t)(displacement >> 24) & 0x1;
+               uint32_t i1 = (uint32_t)(displacement >> 23) & 0x1;
+               uint32_t i2 = (uint32_t)(displacement >> 22) & 0x1;
+               uint32_t imm10 = (uint32_t)(displacement >> 12) & 0x3FF;
+               uint32_t imm11 = (uint32_t)(displacement >> 1) & 0x7FF;
+               uint32_t j1 = (i1 == s);
+               uint32_t j2 = (i2 == s);
+               uint32_t opcode = 0x9000F000;
+               uint32_t nextDisp = (j1 << 13) | (j2 << 11) | imm11;
+               uint32_t firstDisp = (s << 10) | imm10;
+               uint32_t newInstruction = opcode | (nextDisp << 16) | firstDisp;
+               //warning("s=%d, j1=%d, j2=%d, imm10=0x%0X, imm11=0x%0X, opcode=0x%08X, first=0x%04X, next=0x%04X, new=0x%08X, disp=0x%llX for %s to %s\n",
+               //      s, j1, j2, imm10, imm11, opcode, firstDisp, nextDisp, newInstruction, displacement, inAtom->getDisplayName(), ref->getTarget().getDisplayName());
+               OSWriteLittleInt32(buffer, 0, newInstruction);
+       }
+       virtual void                                                    setScope(Scope)                                 { }
+
+private:
+       const char*                                                             _name;
+       const ld::Atom*                                                 _target;
+       TargetAndOffset                                                 _finalTarget;
+};
+
+
+class NoPicARMtoThumbMBranchIslandAtom : public ld::Atom {
+public:
+                                                                                       NoPicARMtoThumbMBranchIslandAtom(const char* nm, const ld::Atom* target, TargetAndOffset finalTarget)
+                               : ld::Atom(_s_text_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeBranchIsland, 
+                                                       ld::Atom::symbolTableIn, false, false, false, ld::Atom::Alignment(2)), 
+                               _name(nm),
+                               _target(target),
+                               _finalTarget(finalTarget) { }
+
+       virtual const ld::File*                                 file() const                                    { return NULL; }
+       virtual bool                                                    translationUnitSource(const char** dir, const char**) const 
+                                                                                                                                                       { return false; }
+       virtual const char*                                             name() const                                    { return _name; }
+       virtual uint64_t                                                size() const                                    { return 8; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+               // There is no large displacement thumb1 branch instruction.
+               // Instead use ARM instructions that can jump to thumb.
+               // we use a 32-bit displacement, so we can directly jump to final target which means no island hopping
+               uint32_t targetAddr = _finalTarget.atom->finalAddress();
+               if ( _finalTarget.atom->isThumb() )
+                       targetAddr |= 1;
+               if (_s_log) fprintf(stderr, "%s: 2 ARM instruction jump to final target at 0x%08llX\n",
+                                                                       _target->name(), _finalTarget.atom->finalAddress());
+               OSWriteLittleInt32(&buffer[0], 0, 0xe51ff004);  //      ldr     pc, [pc, #-4]
+               OSWriteLittleInt32(&buffer[4], 0, targetAddr);  //      .long target-this               
+       }
+       virtual void                                                    setScope(Scope)                                 { }
+
+private:
+       const char*                                                             _name;
+       const ld::Atom*                                                 _target;
+       TargetAndOffset                                                 _finalTarget;
+};
+
+
+static ld::Atom* makeBranchIsland(const Options& opts, ld::Fixup::Kind kind, int islandRegion, const ld::Atom* nextTarget, TargetAndOffset finalTarget)
+{
+       char* name;
+       if ( finalTarget.offset == 0 ) {
+               if ( islandRegion == 0 )
+                       asprintf(&name, "%s.island", finalTarget.atom->name());
+               else
+                       asprintf(&name, "%s.island.%d", finalTarget.atom->name(), islandRegion+1);
+       }
+       else {
+               asprintf(&name, "%s_plus_%d.island.%d", finalTarget.atom->name(), finalTarget.offset, islandRegion);
+       }
+
+       switch ( kind ) {
+               case ld::Fixup::kindStorePPCBranch24:
+               case ld::Fixup::kindStoreTargetAddressPPCBranch24:
+                       return new PPCBranchIslandAtom(name, nextTarget, finalTarget);
+                       break;
+               case ld::Fixup::kindStoreARMBranch24:
+               case ld::Fixup::kindStoreThumbBranch22:
+               case ld::Fixup::kindStoreTargetAddressARMBranch24:
+               case ld::Fixup::kindStoreTargetAddressThumbBranch22:
+                       if ( finalTarget.atom->isThumb() ) {
+                               if ( opts.preferSubArchitecture() && opts.subArchitecture() == CPU_SUBTYPE_ARM_V7 ) {
+                                       return new Thumb2toThumbBranchIslandAtom(name, nextTarget, finalTarget);
+                               }
+                               else if ( opts.outputSlidable() ) {
+                                       return new ARMtoThumb1BranchIslandAtom(name, nextTarget, finalTarget);
+                               }
+                               else {
+                                       return new NoPicARMtoThumbMBranchIslandAtom(name, nextTarget, finalTarget);
+                               }
+                       }
+                       else {
+                               return new ARMtoARMBranchIslandAtom(name, nextTarget, finalTarget);
+                       }
+                       break;
+               default:
+                       assert(0 && "unexpected branch kind");
+                       break;
+       }
+       return NULL;
+}
+
+
+static uint64_t textSizeWhenMightNeedBranchIslands(const Options& opts, bool seenThumbBranch)
+{
+       switch ( opts.architecture() ) {
+               case CPU_TYPE_POWERPC:
+               case CPU_TYPE_POWERPC64:
+                       return 16000000;
+                       break;
+               case CPU_TYPE_ARM:
+                       if ( ! seenThumbBranch )
+                               return 32000000;  // ARM can branch +/- 32MB
+                       else if ( opts.preferSubArchitecture() && opts.subArchitecture() == CPU_SUBTYPE_ARM_V7 ) 
+                               return 16000000;  // thumb2 can branch +/- 16MB
+                       else
+                               return  4000000;  // thumb1 can branch +/- 4MB
+                       break;
+       }
+       assert(0 && "unexpected architecture");
+       return 0x100000000LL;
+}
+
+
+static uint64_t maxDistanceBetweenIslands(const Options& opts, bool seenThumbBranch)
+{
+       switch ( opts.architecture() ) {
+               case CPU_TYPE_POWERPC:
+               case CPU_TYPE_POWERPC64:
+                               return 14*1024*1024;
+                       break;
+               case CPU_TYPE_ARM:
+                       if ( ! seenThumbBranch )
+                               return 30*1024*1024;    // 2MB of branch islands per 32MB
+                       else if ( opts.preferSubArchitecture() && opts.subArchitecture() == CPU_SUBTYPE_ARM_V7 ) 
+                               return 14*1024*1024;    // 2MB of branch islands per 16MB
+                       else
+                               return 3500000;                 // 0.5MB of branch islands per 4MB
+                       break;
+       }
+       assert(0 && "unexpected architecture");
+       return 0x100000000LL;
+}
+
+
+//
+// PowerPC can do PC relative branches as far as +/-16MB.
+// If a branch target is >16MB then we insert one or more
+// "branch islands" between the branch and its target that
+// allows island hopping to the target.
+//
+// Branch Island Algorithm
+//
+// If the __TEXT segment < 16MB, then no branch islands needed
+// Otherwise, every 14MB into the __TEXT segment a region is
+// added which can contain branch islands.  Every out-of-range
+// bl instruction is checked.  If it crosses a region, an island
+// is added to that region with the same target and the bl is
+// adjusted to target the island instead.
+//
+// In theory, if too many islands are added to one region, it
+// could grow the __TEXT enough that other previously in-range
+// bl branches could be pushed out of range.  We reduce the
+// probability this could happen by placing the ranges every
+// 14MB which means the region would have to be 2MB (512,000 islands)
+// before any branches could be pushed out of range.
+//
+
+void doPass(const Options& opts, ld::Internal& state)
+{      
+       // only make branch islands in final linked images
+       if ( opts.outputKind() == Options::kObjectFile )
+               return;
+
+       // only PowerPC and ARM need branch islands
+       switch ( opts.architecture() ) {
+               case CPU_TYPE_POWERPC:
+               case CPU_TYPE_POWERPC64:
+               case CPU_TYPE_ARM:
+                       break;
+               default:
+                       return;
+       }
+       
+       // scan to find __text section
+       ld::Internal::FinalSection* textSection = NULL;
+       for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
+               ld::Internal::FinalSection* sect = *sit;
+               if ( strcmp(sect->sectionName(), "__text") == 0 )
+                       textSection = sect;
+       }
+       if ( textSection == NULL )
+               return;
+       
+       // assign section offsets to each atom in __text section, watch for thumb branches, and find total size
+       const bool isARM = (opts.architecture() == CPU_TYPE_ARM);
+       bool hasThumbBranches = false;
+       uint64_t offset = 0;
+       for (std::vector<const ld::Atom*>::iterator ait=textSection->atoms.begin();  ait != textSection->atoms.end(); ++ait) {
+               const ld::Atom* atom = *ait;
+               // check for thumb branches
+               if ( isARM && ~hasThumbBranches ) {
+                       for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+                               switch ( fit->kind ) {
+                                       case ld::Fixup::kindStoreThumbBranch22:
+                                       case ld::Fixup::kindStoreTargetAddressThumbBranch22:
+                                               hasThumbBranches = true;
+                                               break;
+                                       default:
+                                               break;
+                               }
+                       }
+               }
+               // align atom
+               ld::Atom::Alignment atomAlign = atom->alignment();
+               uint64_t atomAlignP2 = (1 << atomAlign.powerOf2);
+               uint64_t currentModulus = (offset % atomAlignP2);
+               if ( currentModulus != atomAlign.modulus ) {
+                       if ( atomAlign.modulus > currentModulus )
+                               offset += atomAlign.modulus-currentModulus;
+                       else
+                               offset += atomAlign.modulus+atomAlignP2-currentModulus;         
+               }
+               (const_cast<ld::Atom*>(atom))->setSectionOffset(offset);
+               offset += atom->size();
+       }
+       uint64_t totalTextSize = offset;
+       if ( totalTextSize < textSizeWhenMightNeedBranchIslands(opts, hasThumbBranches) )
+               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;
+       typedef std::map<TargetAndOffset,const ld::Atom*, TargetAndOffsetComparor> AtomToIsland;
+    AtomToIsland* regionsMap[kIslandRegionsCount];
+       std::vector<const ld::Atom*>* regionsIslands[kIslandRegionsCount];
+       for(int i=0; i < kIslandRegionsCount; ++i) {
+               regionsMap[i] = new AtomToIsland();
+               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) {
+               const ld::Atom* atom = *ait;
+               const ld::Atom* target = NULL;
+               uint64_t addend = 0;
+               ld::Fixup* fixupWithTarget = NULL;
+               for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+                       if ( fit->firstInCluster() ) {
+                               target = NULL;
+                               fixupWithTarget = NULL;
+                               addend = 0;
+                       }
+                       switch ( fit->binding ) {
+                               case ld::Fixup::bindingNone:
+                               case ld::Fixup::bindingByNameUnbound:
+                                       break;
+                               case ld::Fixup::bindingByContentBound:
+                               case ld::Fixup::bindingDirectlyBound:
+                                       target = fit->u.target;
+                                       fixupWithTarget = fit;
+                                       break;
+                               case ld::Fixup::bindingsIndirectlyBound:
+                                       target = state.indirectBindingTable[fit->u.bindingIndex];
+                                       fixupWithTarget = fit;
+                                       break;
+                       }
+                       bool haveBranch = false;
+                       switch (fit->kind) {
+                               case ld::Fixup::kindAddAddend:
+                                       addend = fit->u.addend;
+                                       break;
+                               case ld::Fixup::kindStorePPCBranch24:
+                               case ld::Fixup::kindStoreTargetAddressPPCBranch24:
+                               case ld::Fixup::kindStoreARMBranch24:
+                               case ld::Fixup::kindStoreThumbBranch22:
+                               case ld::Fixup::kindStoreTargetAddressARMBranch24:
+                               case ld::Fixup::kindStoreTargetAddressThumbBranch22:
+                                       haveBranch = true;
+                                       break;
+                default:
+                    break;   
+                       }
+                       if ( haveBranch ) {
+                               int64_t srcAddr = atom->sectionOffset() + fit->offsetInAtom;
+                               int64_t dstAddr = target->sectionOffset() + addend;
+                               if ( target->section().type() == ld::Section::typeStub )
+                                       dstAddr = totalTextSize;
+                               int64_t displacement = dstAddr - srcAddr;
+                               TargetAndOffset finalTargetAndOffset = { target, addend };
+                               const int64_t kBranchLimit = kBetweenRegions;
+                               if ( displacement > kBranchLimit ) {
+                                       // create forward branch chain
+                                       const ld::Atom* nextTarget = target;
+                                       for (int i=kIslandRegionsCount-1; i >=0 ; --i) {
+                                               AtomToIsland* region = regionsMap[i];
+                                               int64_t islandRegionAddr = kBetweenRegions * (i+1);
+                                               if ( (srcAddr < islandRegionAddr) && (islandRegionAddr <= dstAddr) ) { 
+                                                       AtomToIsland::iterator pos = region->find(finalTargetAndOffset);
+                                                       if ( pos == region->end() ) {
+                                                               ld::Atom* island = makeBranchIsland(opts, fit->kind, i, nextTarget, finalTargetAndOffset);
+                                                               (*region)[finalTargetAndOffset] = island;
+                                                               if (_s_log) fprintf(stderr, "added island %s to region %d for %s\n", island->name(), i, atom->name());
+                                                               regionsIslands[i]->push_back(island);
+                                                               ++islandCount;
+                                                               nextTarget = island;
+                                                       }
+                                                       else {
+                                                               nextTarget = pos->second;
+                                                       }
+                                               }
+                                       }
+                                       if (_s_log) fprintf(stderr, "using island %s for branch to %s from %s\n", nextTarget->name(), target->name(), atom->name());
+                                       fixupWithTarget->u.target = nextTarget;
+                                       fixupWithTarget->binding = ld::Fixup::bindingDirectlyBound;
+                               }
+                               else if ( displacement < (-kBranchLimit) ) {
+                                       // create back branching chain
+                                       const ld::Atom* prevTarget = target;
+                                       for (int i=0; i < kIslandRegionsCount ; ++i) {
+                                               AtomToIsland* region = regionsMap[i];
+                                               int64_t islandRegionAddr = kBetweenRegions * (i+1);
+                                               if ( (dstAddr <= islandRegionAddr) && (islandRegionAddr < srcAddr) ) {
+                                                       AtomToIsland::iterator pos = region->find(finalTargetAndOffset);
+                                                       if ( pos == region->end() ) {
+                                                               ld::Atom* island = makeBranchIsland(opts, fit->kind, i, prevTarget, finalTargetAndOffset);
+                                                               (*region)[finalTargetAndOffset] = island;
+                                                               if (_s_log) fprintf(stderr, "added back island %s to region %d for %s\n", island->name(), i, atom->name());
+                                                               regionsIslands[i]->push_back(island);
+                                                               ++islandCount;
+                                                               prevTarget = island;
+                                                       }
+                                                       else {
+                                                               prevTarget = pos->second;
+                                                       }
+                                               }
+                                       }
+                                       if (_s_log) fprintf(stderr, "using back island %s for %s\n", prevTarget->name(), atom->name());
+                                       fixupWithTarget->u.target = prevTarget;
+                                       fixupWithTarget->binding = ld::Fixup::bindingDirectlyBound;
+                               }
+                       }
+               }
+       }
+
+
+       // insert islands into __text section and adjust section offsets
+       if ( islandCount > 0 ) {
+               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;
+                       }
+                       newAtomList.push_back(atom);
+               }
+               // put any remaining islands at end of __text section
+               if ( regionIndex < kIslandRegionsCount ) {
+                       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());
+                       }
+               }
+               // swap in new list of atoms for __text section
+               textSection->atoms.clear();
+               textSection->atoms = newAtomList;
+       }
+
+}
+
+
+} // namespace branch_island
+} // namespace passes 
+} // namespace ld 
diff --git a/src/ld/passes/branch_island.h b/src/ld/passes/branch_island.h
new file mode 100644 (file)
index 0000000..5daafe4
--- /dev/null
@@ -0,0 +1,45 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#ifndef __BRANCH_ISLAND_H__
+#define __BRANCH_ISLAND_H__
+
+#include "Options.h"
+#include "ld.hpp"
+
+
+namespace ld {
+namespace passes {
+namespace branch_island {
+
+// called by linker to branch islands if there are out of range branches
+extern void doPass(const Options& opts, ld::Internal& internal);
+
+
+} // namespace branch_island
+} // namespace passes 
+} // namespace ld 
+
+#endif // __BRANCH_ISLAND_H__
diff --git a/src/ld/passes/branch_shim.cpp b/src/ld/passes/branch_shim.cpp
new file mode 100644 (file)
index 0000000..70ebcfc
--- /dev/null
@@ -0,0 +1,314 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <stdint.h>
+#include <math.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <vector>
+#include <map>
+
+#include "MachOFileAbstraction.hpp"
+#include "ld.hpp"
+#include "branch_shim.h"
+
+namespace ld {
+namespace passes {
+namespace branch_shim {
+
+
+
+static bool _s_log = false;
+static ld::Section _s_text_section("__TEXT", "__text", ld::Section::typeCode);
+
+
+
+class Thumb2ToArmShimAtom : public ld::Atom {
+public:
+                                                                                       Thumb2ToArmShimAtom(const ld::Atom* target)
+                               : ld::Atom(_s_text_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified, 
+                                                       ld::Atom::symbolTableIn, false, true, false, ld::Atom::Alignment(1)), 
+                               _name(NULL),
+                               _target(target),
+                               _fixup1(8, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, target),
+                               _fixup2(8, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, this),
+                               _fixup3(8, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, 8),
+                               _fixup4(8, ld::Fixup::k4of4, ld::Fixup::kindStoreLittleEndian32)
+                                { asprintf((char**)&_name, "%s$shim", target->name()); }
+
+       virtual const ld::File*                                 file() const                                    { return NULL; }
+       virtual bool                                                    translationUnitSource(const char** dir, const char**) const 
+                                                                                                                                                       { return false; }
+       virtual const char*                                             name() const                                    { return _name; }
+       virtual uint64_t                                                size() const                                    { return 12; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+               // Use ARM instructions that can jump to thumb.
+               assert( !  _target->isThumb() );
+               if (_s_log) fprintf(stderr, "3 Thumb2 instruction shim to jump to %s\n", _target->name());
+               OSWriteLittleInt32(&buffer[0], 0, 0xc004f8df);  //      ldr  ip, pc + 4
+               OSWriteLittleInt16(&buffer[4], 0, 0x44fc);              //      add      ip, pc, ip
+               OSWriteLittleInt16(&buffer[6], 0, 0x4760);              //      bx       ip
+               OSWriteLittleInt32(&buffer[8], 0, 0x00000000);  //      .long target-this               
+       }
+
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return (ld::Fixup*)&_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup4)[1]; }
+
+private:
+       const char*                                                             _name;
+       const ld::Atom*                                                 _target;
+       ld::Fixup                                                               _fixup1;
+       ld::Fixup                                                               _fixup2;
+       ld::Fixup                                                               _fixup3;
+       ld::Fixup                                                               _fixup4;
+};
+
+
+
+class Thumb1ToArmShimAtom : public ld::Atom {
+public:
+                                                                                       Thumb1ToArmShimAtom(const ld::Atom* target)
+                               : ld::Atom(_s_text_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified, 
+                                                       ld::Atom::symbolTableIn, false, true, false, ld::Atom::Alignment(1)), 
+                               _name(NULL),
+                               _target(target),
+                               _fixup1(12, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, target),
+                               _fixup2(12, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, this),
+                               _fixup3(12, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, 8),
+                               _fixup4(12, ld::Fixup::k4of4, ld::Fixup::kindStoreLittleEndian32)
+                                { asprintf((char**)&_name, "%s$shim", target->name()); }
+
+       virtual const ld::File*                                 file() const                                    { return NULL; }
+       virtual bool                                                    translationUnitSource(const char** dir, const char**) 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 {
+               // Use ARM instructions that can jump to thumb.
+               assert( ! _target->isThumb() );
+               if (_s_log) fprintf(stderr, "6 Thumb1 instruction shim to jump to %s\n", _target->name());
+               OSWriteLittleInt16(&buffer[ 0], 0, 0xb402);             //      push    {r1}
+               OSWriteLittleInt16(&buffer[ 2], 0, 0x4902);             //      ldr             r1, [pc, #8]
+               OSWriteLittleInt16(&buffer[ 4], 0, 0x4479);             //      add             r1, pc
+               OSWriteLittleInt16(&buffer[ 6], 0, 0x468c);             //      mov             ip, r1
+               OSWriteLittleInt16(&buffer[ 8], 0, 0xbc02);             //      pop             {r1}
+               OSWriteLittleInt16(&buffer[10], 0, 0x4760);             //      bx              ip
+               OSWriteLittleInt32(&buffer[12], 0, 0x00000000); //      .long target-this               
+       }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return (ld::Fixup*)&_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup4)[1]; }
+
+private:
+       const char*                                                             _name;
+       const ld::Atom*                                                 _target;
+       ld::Fixup                                                               _fixup1;
+       ld::Fixup                                                               _fixup2;
+       ld::Fixup                                                               _fixup3;
+       ld::Fixup                                                               _fixup4;
+};
+
+
+
+
+class ARMtoThumbShimAtom : public ld::Atom {
+public:
+                                                                                       ARMtoThumbShimAtom(const ld::Atom* target)
+                               : ld::Atom(_s_text_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified, 
+                                                       ld::Atom::symbolTableIn, false, false, false, ld::Atom::Alignment(2)), 
+                               _name(NULL),
+                               _target(target),
+                               _fixup1(12, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, target),
+                               _fixup2(12, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, this),
+                               _fixup3(12, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, 12),
+                               _fixup4(12, ld::Fixup::k4of4, ld::Fixup::kindStoreLittleEndian32)
+                                { asprintf((char**)&_name, "%s$shim", target->name()); }
+
+       virtual const ld::File*                                 file() const                                    { return NULL; }
+       virtual bool                                                    translationUnitSource(const char** dir, const char**) 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 {
+               // Use ARM instructions that can jump to thumb.
+               assert( _target->isThumb() );
+               if (_s_log) fprintf(stderr, "4 ARM instruction shim to jump to %s\n", _target->name());
+               OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc004); //      ldr  ip, pc + 4
+               OSWriteLittleInt32(&buffer[ 4], 0, 0xe08fc00c); //      add      ip, pc, ip
+               OSWriteLittleInt32(&buffer[ 8], 0, 0xe12fff1c); //      bx       ip
+               OSWriteLittleInt32(&buffer[12], 0, 0);                  //      .long target-this               
+       }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return (ld::Fixup*)&_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup4)[1]; }
+
+private:
+       const char*                                                             _name;
+       const ld::Atom*                                                 _target;
+       ld::Fixup                                                               _fixup1;
+       ld::Fixup                                                               _fixup2;
+       ld::Fixup                                                               _fixup3;
+       ld::Fixup                                                               _fixup4;
+};
+
+
+
+
+
+
+static void extractTarget(ld::Fixup::iterator fixup, ld::Internal& state, const ld::Atom** target)
+{
+       switch ( fixup->binding ) {
+               case ld::Fixup::bindingNone:
+                       throw "unexpected bindingNone";
+               case ld::Fixup::bindingByNameUnbound:
+                       throw "unexpected bindingByNameUnbound";
+               case ld::Fixup::bindingByContentBound:
+               case ld::Fixup::bindingDirectlyBound:
+                       *target = fixup->u.target;
+                       break;
+               case ld::Fixup::bindingsIndirectlyBound:
+                       *target = state.indirectBindingTable[fixup->u.bindingIndex];
+                       break;
+       }
+}
+
+
+
+//
+// The tail-call optimzation may result in a function ending in a jump (b) 
+// to another functions.  At compile time the compiler does not know 
+// if the target of the jump will be in the same mode (arm vs thumb).
+// The arm/thumb instruction set has a way to change modes in a bl(x)
+// insruction, but no instruction to change mode in a jump (b) instruction.
+// In those rare cases, the linker needs to insert a shim of code to 
+// make the mode switch.
+//
+void doPass(const Options& opts, ld::Internal& state)
+{      
+       std::map<const Atom*, const Atom*> atomToThumbMap;
+       std::map<const Atom*, const Atom*> thumbToAtomMap;
+       std::vector<const Atom*> shims;
+
+       // only make branch shims in final linked images
+       if ( opts.outputKind() == Options::kObjectFile )
+               return;
+
+       // only ARM need branch islands
+       if ( opts.architecture() != CPU_TYPE_ARM )
+               return;
+       
+       // scan to find __text section
+       ld::Internal::FinalSection* textSection = NULL;
+       for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
+               ld::Internal::FinalSection* sect = *sit;
+               if ( strcmp(sect->sectionName(), "__text") == 0 )
+                       textSection = sect;
+       }
+       if ( textSection == NULL )
+               return;
+       
+       // scan __text section for branch instructions that need to switch mode
+       for (std::vector<const ld::Atom*>::iterator ait=textSection->atoms.begin();  ait != textSection->atoms.end(); ++ait) {
+               const ld::Atom* atom = *ait;
+               const ld::Atom* target;
+               for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+                       switch ( fit->kind ) {
+                               case ld::Fixup::kindStoreTargetAddressThumbBranch22:
+                                       extractTarget(fit, state, &target);
+                                       if ( ! target->isThumb() ) {
+                                               const uint8_t* fixUpLocation = atom->rawContentPointer() + fit->offsetInAtom;
+                                               uint32_t instruction = *((uint32_t*)fixUpLocation);
+                                               bool is_b = ((instruction & 0xD000F800) == 0x9000F000);
+                                               if ( is_b ) {
+                                                       fprintf(stderr, "need to add thumb->arm instr=0x%08X shim to %s for %s\n", instruction, target->name(), atom->name()); 
+                                                       const Atom* shim = NULL;
+                                                       std::map<const Atom*, const Atom*>::iterator pos = thumbToAtomMap.find(target);
+                                                       if ( pos == thumbToAtomMap.end() ) {
+                                                               if ( opts.subArchitecture() == CPU_SUBTYPE_ARM_V7 )
+                                                                       shim = new Thumb2ToArmShimAtom(target);
+                                                               else
+                                                                       shim = new Thumb1ToArmShimAtom(target);
+                                                               shims.push_back(shim);
+                                                               thumbToAtomMap[target] = shim;
+                                                       }
+                                                       else {
+                                                               shim = pos->second;
+                                                       }
+                                                       fit->binding = ld::Fixup::bindingDirectlyBound;
+                                                       fit->u.target = shim;
+                                               }
+                                       }
+                                       break;
+                               case ld::Fixup::kindStoreTargetAddressARMBranch24:
+                                       extractTarget(fit, state, &target);
+                                       if ( target->isThumb() ) {
+                                               const uint8_t* fixUpLocation = atom->rawContentPointer() + fit->offsetInAtom;
+                                               uint32_t instruction = *((uint32_t*)fixUpLocation);
+                                               bool is_b = ((instruction & 0x0F000000) == 0x0A000000);
+                                               if ( is_b ) {
+                                                       fprintf(stderr, "need to add arm->thumb instr=0x%08X shim to %s for %s\n", instruction, target->name(), atom->name()); 
+                                                       const Atom* shim = NULL;
+                                                       std::map<const Atom*, const Atom*>::iterator pos = atomToThumbMap.find(target);
+                                                       if ( pos == atomToThumbMap.end() ) {
+                                                               shim = new ARMtoThumbShimAtom(target);
+                                                               shims.push_back(shim);
+                                                               atomToThumbMap[target] = shim;
+                                                       }
+                                                       else {
+                                                               shim = pos->second;
+                                                       }
+                                                       fit->binding = ld::Fixup::bindingDirectlyBound;
+                                                       fit->u.target = shim;
+                                               }
+                                       }
+                                       break;
+                               
+                               case ld::Fixup::kindStoreARMBranch24:
+                               case ld::Fixup::kindStoreThumbBranch22:
+                                       fprintf(stderr, "found branch-22 without store in %s\n", atom->name()); 
+                                       break;
+                               default:
+                                       break;
+                       }
+               }
+       }
+
+       // append all new shims to end of __text
+       textSection->atoms.insert(textSection->atoms.end(), shims.begin(), shims.end());
+}
+
+
+} // namespace branch_shim
+} // namespace passes 
+} // namespace ld 
diff --git a/src/ld/passes/branch_shim.h b/src/ld/passes/branch_shim.h
new file mode 100644 (file)
index 0000000..ab6b959
--- /dev/null
@@ -0,0 +1,45 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#ifndef __BRANCH_SHIM_H__
+#define __BRANCH_SHIM_H__
+
+#include "Options.h"
+#include "ld.hpp"
+
+
+namespace ld {
+namespace passes {
+namespace branch_shim {
+
+// called by linker to branch shims to support branch (but not bl) that switches mode
+extern void doPass(const Options& opts, ld::Internal& internal);
+
+
+} // namespace branch_shim
+} // namespace passes 
+} // namespace ld 
+
+#endif // __BRANCH_SHIM_H__
diff --git a/src/ld/passes/compact_unwind.cpp b/src/ld/passes/compact_unwind.cpp
new file mode 100644 (file)
index 0000000..5b9434e
--- /dev/null
@@ -0,0 +1,794 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <stdint.h>
+#include <math.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <mach/machine.h>
+#include <mach-o/compact_unwind_encoding.h>
+
+#include <vector>
+#include <map>
+
+#include "ld.hpp"
+#include "compact_unwind.h"
+#include "Architectures.hpp"
+#include "MachOFileAbstraction.hpp"
+
+
+namespace ld {
+namespace passes {
+namespace compact_unwind {
+
+
+struct UnwindEntry { 
+                                               UnwindEntry(const ld::Atom* f, uint64_t a, uint32_t o, const ld::Atom* d, 
+                                                                                                                       const ld::Atom* l, const ld::Atom* p, uint32_t en)
+                                                       : func(f), fde(d), lsda(l), personalityPointer(p), funcTentAddress(a), 
+                                                               functionOffset(o), encoding(en) { }
+       const ld::Atom*                         func; 
+       const ld::Atom*                         fde; 
+       const ld::Atom*                         lsda; 
+       const ld::Atom*                         personalityPointer; 
+       uint64_t                                        funcTentAddress;
+       uint32_t                                        functionOffset;
+       compact_unwind_encoding_t       encoding; 
+};
+
+struct LSDAEntry { 
+       const ld::Atom*         func; 
+       const ld::Atom*         lsda; 
+};
+
+
+template <typename A>
+class UnwindInfoAtom : public ld::Atom {
+public:
+                                                                                       UnwindInfoAtom(const std::vector<UnwindEntry>& entries,uint64_t ehFrameSize);
+                                                                                       ~UnwindInfoAtom();
+                                                                                       
+       virtual const ld::File*                                 file() const                                    { return NULL; }
+       virtual bool                                                    translationUnitSource(const char** dir, const char**) const 
+                                                                                                                                                       { return false; }
+       virtual const char*                                             name() const                                    { return "compact unwind info"; }
+       virtual uint64_t                                                size() const                                    { return _headerSize+_pagesSize; }
+       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*)&_fixups[0]; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return (ld::Fixup*)&_fixups[_fixups.size()]; }
+
+private:
+       typedef typename A::P                                           P;
+       typedef typename A::P::E                                        E;
+       typedef typename A::P::uint_t                           pint_t;
+
+       typedef macho_unwind_info_compressed_second_level_page_header<P> CSLP;
+
+       bool                                            encodingMeansUseDwarf(compact_unwind_encoding_t enc);
+       void                                            compressDuplicates(const std::vector<UnwindEntry>& entries, 
+                                                                                                       std::vector<UnwindEntry>& uniqueEntries);
+       void                                            makePersonalityIndexes(std::vector<UnwindEntry>& entries, 
+                                                                                                               std::map<const ld::Atom*, uint32_t>& personalityIndexMap);
+       void                                            findCommonEncoding(const std::vector<UnwindEntry>& entries, 
+                                                                                                       std::map<compact_unwind_encoding_t, unsigned int>& commonEncodings);
+       void                                            makeLsdaIndex(const std::vector<UnwindEntry>& entries, std::vector<LSDAEntry>& lsdaIndex, 
+                                                                                                                               std::map<const ld::Atom*, uint32_t>& lsdaIndexOffsetMap);
+       unsigned int                            makeCompressedSecondLevelPage(const std::vector<UnwindEntry>& uniqueInfos,   
+                                                                                                       const std::map<compact_unwind_encoding_t,unsigned int> commonEncodings,  
+                                                                                                       uint32_t pageSize, unsigned int endIndex, uint8_t*& pageEnd);
+       unsigned int                            makeRegularSecondLevelPage(const std::vector<UnwindEntry>& uniqueInfos, uint32_t pageSize,  
+                                                                                                                       unsigned int endIndex, uint8_t*& pageEnd);
+       void                                            addCompressedAddressOffsetFixup(uint32_t offset, const ld::Atom* func, const ld::Atom* fromFunc);
+       void                                            addCompressedEncodingFixup(uint32_t offset, const ld::Atom* fde);
+       void                                            addRegularAddressFixup(uint32_t offset, const ld::Atom* func);
+       void                                            addRegularFDEOffsetFixup(uint32_t offset, const ld::Atom* fde);
+       void                                            addImageOffsetFixup(uint32_t offset, const ld::Atom* targ);
+       void                                            addImageOffsetFixupPlusAddend(uint32_t offset, const ld::Atom* targ, uint32_t addend);
+
+       uint8_t*                                                                _pagesForDelete;
+       uint8_t*                                                                _pages;
+       uint64_t                                                                _pagesSize;
+       uint8_t*                                                                _header;
+       uint64_t                                                                _headerSize;
+       std::vector<ld::Fixup>                                  _fixups;
+       
+       static bool                                                             _s_log;
+       static ld::Section                                              _s_section;
+};
+
+template <typename A>
+bool UnwindInfoAtom<A>::_s_log = false;
+
+template <typename A>
+ld::Section UnwindInfoAtom<A>::_s_section("__TEXT", "__unwind_info", ld::Section::typeUnwindInfo);
+
+
+template <typename A>
+UnwindInfoAtom<A>::UnwindInfoAtom(const std::vector<UnwindEntry>& entries, uint64_t ehFrameSize)
+       : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                               ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified, 
+                               symbolTableNotIn, false, false, false, ld::Atom::Alignment(0)),
+               _pagesForDelete(NULL), _pages(NULL), _pagesSize(0), _header(NULL), _headerSize(0)
+{
+       // build new compressed list by removing entries where next function has same encoding 
+       std::vector<UnwindEntry> uniqueEntries;
+       compressDuplicates(entries, uniqueEntries);
+
+       // reserve room so _fixups vector is not reallocated a bunch of times
+       _fixups.reserve(uniqueEntries.size()*3);
+
+       // build personality index, update encodings with personality index
+       std::map<const ld::Atom*, uint32_t>     personalityIndexMap;
+       makePersonalityIndexes(uniqueEntries, personalityIndexMap);
+       if ( personalityIndexMap.size() > 3 ) {
+               warning("too many personality routines for compact unwind to encode");
+               return;
+       }
+
+       // put the most common encodings into the common table, but at most 127 of them
+       std::map<compact_unwind_encoding_t, unsigned int> commonEncodings;
+       findCommonEncoding(uniqueEntries, commonEncodings);
+       
+       // build lsda index
+       std::map<const ld::Atom*, uint32_t> lsdaIndexOffsetMap;
+       std::vector<LSDAEntry>  lsdaIndex;
+       makeLsdaIndex(uniqueEntries, lsdaIndex, lsdaIndexOffsetMap);
+       
+       
+       // calculate worst case size for all unwind info pages when allocating buffer
+       const unsigned int entriesPerRegularPage = (4096-sizeof(unwind_info_regular_second_level_page_header))/sizeof(unwind_info_regular_second_level_entry);
+       assert(uniqueEntries.size() > 0);
+       const unsigned int pageCount = ((uniqueEntries.size() - 1)/entriesPerRegularPage) + 1;
+       _pagesForDelete = (uint8_t*)calloc(pageCount,4096);
+       if ( _pagesForDelete == NULL ) {
+               warning("could not allocate space for compact unwind info");
+               return;
+       }
+       
+       // make last second level page smaller so that all other second level pages can be page aligned
+       uint32_t maxLastPageSize = 4096 - (ehFrameSize % 4096);
+       uint32_t tailPad = 0;
+       if ( maxLastPageSize < 128 ) {
+               tailPad = maxLastPageSize;
+               maxLastPageSize = 4096;
+       }
+       
+       // fill in pages in reverse order
+       const ld::Atom* secondLevelFirstFuncs[pageCount*3];
+       uint8_t* secondLevelPagesStarts[pageCount*3];
+       unsigned int endIndex = uniqueEntries.size();
+       unsigned int secondLevelPageCount = 0;
+       uint8_t* pageEnd = &_pagesForDelete[pageCount*4096];
+       uint32_t pageSize = maxLastPageSize;
+       while ( endIndex > 0 ) {
+               endIndex = makeCompressedSecondLevelPage(uniqueEntries, commonEncodings, pageSize, endIndex, pageEnd);
+               secondLevelPagesStarts[secondLevelPageCount] = pageEnd;
+               secondLevelFirstFuncs[secondLevelPageCount] = uniqueEntries[endIndex].func;
+               ++secondLevelPageCount;
+               pageSize = 4096;  // last page can be odd size, make rest up to 4096 bytes in size
+       }
+       _pages = pageEnd;
+       _pagesSize = &_pagesForDelete[pageCount*4096] - pageEnd;
+       
+       
+       // calculate section layout
+       const uint32_t commonEncodingsArraySectionOffset = sizeof(macho_unwind_info_section_header<P>);
+       const uint32_t commonEncodingsArrayCount = commonEncodings.size();
+       const uint32_t commonEncodingsArraySize = commonEncodingsArrayCount * sizeof(compact_unwind_encoding_t);
+       const uint32_t personalityArraySectionOffset = commonEncodingsArraySectionOffset + commonEncodingsArraySize;
+       const uint32_t personalityArrayCount = personalityIndexMap.size();
+       const uint32_t personalityArraySize = personalityArrayCount * sizeof(uint32_t);
+       const uint32_t indexSectionOffset = personalityArraySectionOffset + personalityArraySize;
+       const uint32_t indexCount = secondLevelPageCount+1;
+       const uint32_t indexSize = indexCount * sizeof(macho_unwind_info_section_header_index_entry<P>);
+       const uint32_t lsdaIndexArraySectionOffset = indexSectionOffset + indexSize;
+       const uint32_t lsdaIndexArrayCount = lsdaIndex.size();
+       const uint32_t lsdaIndexArraySize = lsdaIndexArrayCount * sizeof(macho_unwind_info_section_header_lsda_index_entry<P>);
+       const uint32_t headerEndSectionOffset = lsdaIndexArraySectionOffset + lsdaIndexArraySize;
+
+       // now that we know the size of the header, slide all existing fixups on the pages
+       const int32_t fixupSlide = headerEndSectionOffset + (_pagesForDelete - _pages);
+       for(std::vector<ld::Fixup>::iterator it = _fixups.begin(); it != _fixups.end(); ++it) {
+               it->offsetInAtom += fixupSlide;
+       }
+
+       // allocate and fill in section header
+       _headerSize = headerEndSectionOffset;
+       _header = new uint8_t[_headerSize];
+       bzero(_header, _headerSize);
+       macho_unwind_info_section_header<P>* sectionHeader = (macho_unwind_info_section_header<P>*)_header;
+       sectionHeader->set_version(UNWIND_SECTION_VERSION);
+       sectionHeader->set_commonEncodingsArraySectionOffset(commonEncodingsArraySectionOffset);
+       sectionHeader->set_commonEncodingsArrayCount(commonEncodingsArrayCount);
+       sectionHeader->set_personalityArraySectionOffset(personalityArraySectionOffset);
+       sectionHeader->set_personalityArrayCount(personalityArrayCount);
+       sectionHeader->set_indexSectionOffset(indexSectionOffset);
+       sectionHeader->set_indexCount(indexCount);
+       
+       // copy common encodings
+       uint32_t* commonEncodingsTable = (uint32_t*)&_header[commonEncodingsArraySectionOffset];
+       for (std::map<uint32_t, unsigned int>::iterator it=commonEncodings.begin(); it != commonEncodings.end(); ++it)
+               E::set32(commonEncodingsTable[it->second], it->first);
+               
+       // make references for personality entries
+       uint32_t* personalityArray = (uint32_t*)&_header[sectionHeader->personalityArraySectionOffset()];
+       for (std::map<const ld::Atom*, unsigned int>::iterator it=personalityIndexMap.begin(); it != personalityIndexMap.end(); ++it) {
+               uint32_t offset = (uint8_t*)&personalityArray[it->second-1] - _header;
+               this->addImageOffsetFixup(offset, it->first);
+       }
+
+       // build first level index and references
+       macho_unwind_info_section_header_index_entry<P>* indexTable = (macho_unwind_info_section_header_index_entry<P>*)&_header[indexSectionOffset];
+       uint32_t refOffset;
+       for (unsigned int i=0; i < secondLevelPageCount; ++i) {
+               unsigned int reverseIndex = secondLevelPageCount - 1 - i;
+               indexTable[i].set_functionOffset(0);
+               indexTable[i].set_secondLevelPagesSectionOffset(secondLevelPagesStarts[reverseIndex]-_pages+headerEndSectionOffset);
+               indexTable[i].set_lsdaIndexArraySectionOffset(lsdaIndexOffsetMap[secondLevelFirstFuncs[reverseIndex]]+lsdaIndexArraySectionOffset); 
+               refOffset = (uint8_t*)&indexTable[i] - _header;
+               this->addImageOffsetFixup(refOffset, secondLevelFirstFuncs[reverseIndex]);
+       }
+       indexTable[secondLevelPageCount].set_functionOffset(0);
+       indexTable[secondLevelPageCount].set_secondLevelPagesSectionOffset(0);
+       indexTable[secondLevelPageCount].set_lsdaIndexArraySectionOffset(lsdaIndexArraySectionOffset+lsdaIndexArraySize); 
+       refOffset = (uint8_t*)&indexTable[secondLevelPageCount] - _header;
+       this->addImageOffsetFixupPlusAddend(refOffset, entries.back().func, entries.back().func->size()+1);
+       
+       // build lsda references
+       uint32_t lsdaEntrySectionOffset = lsdaIndexArraySectionOffset;
+       for (std::vector<LSDAEntry>::iterator it = lsdaIndex.begin(); it != lsdaIndex.end(); ++it) {
+               this->addImageOffsetFixup(lsdaEntrySectionOffset, it->func);
+               this->addImageOffsetFixup(lsdaEntrySectionOffset+4, it->lsda);
+               lsdaEntrySectionOffset += sizeof(unwind_info_section_header_lsda_index_entry);
+       }
+       
+}
+
+template <typename A>
+UnwindInfoAtom<A>::~UnwindInfoAtom()
+{
+       free(_pagesForDelete);
+       free(_header);
+}
+
+template <typename A>
+void UnwindInfoAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+       // content is in two parts
+       memcpy(buffer, _header, _headerSize);
+       memcpy(&buffer[_headerSize], _pages, _pagesSize);
+}
+
+
+template <>
+bool UnwindInfoAtom<x86>::encodingMeansUseDwarf(compact_unwind_encoding_t enc)
+{
+       return ((enc & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF);
+}
+
+template <>
+bool UnwindInfoAtom<x86_64>::encodingMeansUseDwarf(compact_unwind_encoding_t enc)
+{
+       return ((enc & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF);
+}
+
+template <typename A>
+void UnwindInfoAtom<A>::compressDuplicates(const std::vector<UnwindEntry>& entries, std::vector<UnwindEntry>& uniqueEntries)
+{
+       // build new list removing entries where next function has same encoding 
+       uniqueEntries.reserve(entries.size());
+       UnwindEntry last(NULL, 0, 0, NULL, NULL, NULL, 0xFFFFFFFF);
+       for(std::vector<UnwindEntry>::const_iterator it=entries.begin(); it != entries.end(); ++it) {
+               const UnwindEntry& next = *it;
+               bool newNeedsDwarf = encodingMeansUseDwarf(next.encoding);
+               // remove entries which have same encoding and personalityPointer as last one
+               if ( newNeedsDwarf || (next.encoding != last.encoding) || (next.personalityPointer != last.personalityPointer) 
+                                               || (next.lsda != NULL) || (last.lsda != NULL) ) {
+                       uniqueEntries.push_back(next);
+               }
+               last = next;
+       }
+       if (_s_log) fprintf(stderr, "compressDuplicates() entries.size()=%lu, uniqueEntries.size()=%lu\n", 
+                                                               entries.size(), uniqueEntries.size());
+}
+
+template <typename A>
+void UnwindInfoAtom<A>::makePersonalityIndexes(std::vector<UnwindEntry>& entries, std::map<const ld::Atom*, uint32_t>& personalityIndexMap)
+{
+       for(std::vector<UnwindEntry>::iterator it=entries.begin(); it != entries.end(); ++it) {
+               if ( it->personalityPointer != NULL ) {
+                       std::map<const ld::Atom*, uint32_t>::iterator pos = personalityIndexMap.find(it->personalityPointer);
+                       if ( pos == personalityIndexMap.end() ) {
+                               const uint32_t nextIndex = personalityIndexMap.size() + 1;
+                               personalityIndexMap[it->personalityPointer] = nextIndex;
+                       }
+                       uint32_t personalityIndex = personalityIndexMap[it->personalityPointer];
+                       it->encoding |= (personalityIndex << (__builtin_ctz(UNWIND_PERSONALITY_MASK)) );
+               }
+       }
+       if (_s_log) fprintf(stderr, "makePersonalityIndexes() %lu personality routines used\n", personalityIndexMap.size()); 
+}
+
+
+template <typename A>
+void UnwindInfoAtom<A>::findCommonEncoding(const std::vector<UnwindEntry>& entries, 
+                                                                                       std::map<compact_unwind_encoding_t, unsigned int>& commonEncodings)
+{
+       // scan infos to get frequency counts for each encoding
+       std::map<compact_unwind_encoding_t, unsigned int> encodingsUsed;
+       unsigned int mostCommonEncodingUsageCount = 0;
+       for(std::vector<UnwindEntry>::const_iterator it=entries.begin(); it != entries.end(); ++it) {
+               // never put dwarf into common table
+               if ( encodingMeansUseDwarf(it->encoding) )
+                       continue;
+               std::map<compact_unwind_encoding_t, unsigned int>::iterator pos = encodingsUsed.find(it->encoding);
+               if ( pos == encodingsUsed.end() ) {
+                       encodingsUsed[it->encoding] = 1;
+               }
+               else {
+                       encodingsUsed[it->encoding] += 1;
+                       if ( mostCommonEncodingUsageCount < encodingsUsed[it->encoding] )
+                               mostCommonEncodingUsageCount = encodingsUsed[it->encoding];
+               }
+       }
+       // put the most common encodings into the common table, but at most 127 of them
+       for(unsigned int usages=mostCommonEncodingUsageCount; usages > 1; --usages) {
+               for (std::map<compact_unwind_encoding_t, unsigned int>::iterator euit=encodingsUsed.begin(); euit != encodingsUsed.end(); ++euit) {
+                       if ( euit->second == usages ) {
+                               unsigned int sz = commonEncodings.size();
+                               if ( sz < 127 ) {
+                                       commonEncodings[euit->first] = sz;
+                               }
+                       }
+               }
+       }
+       if (_s_log) fprintf(stderr, "findCommonEncoding() %lu common encodings found\n", commonEncodings.size()); 
+}
+
+
+template <typename A>
+void UnwindInfoAtom<A>::makeLsdaIndex(const std::vector<UnwindEntry>& entries, std::vector<LSDAEntry>& lsdaIndex, std::map<const ld::Atom*, uint32_t>& lsdaIndexOffsetMap)
+{
+       for(std::vector<UnwindEntry>::const_iterator it=entries.begin(); it != entries.end(); ++it) {
+               lsdaIndexOffsetMap[it->func] = lsdaIndex.size() * sizeof(unwind_info_section_header_lsda_index_entry);
+               if ( it->lsda != NULL ) {
+                       LSDAEntry entry;
+                       entry.func = it->func;
+                       entry.lsda = it->lsda;
+                       lsdaIndex.push_back(entry);
+               }
+       }
+       if (_s_log) fprintf(stderr, "makeLsdaIndex() %lu LSDAs found\n", lsdaIndex.size()); 
+}
+
+
+template <>
+void UnwindInfoAtom<x86>::addCompressedAddressOffsetFixup(uint32_t offset, const ld::Atom* func, const ld::Atom* fromFunc)
+{
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of3, ld::Fixup::kindSetTargetAddress, func));
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of3, ld::Fixup::kindSubtractTargetAddress, fromFunc));
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndianLow24of32));
+}
+
+template <>
+void UnwindInfoAtom<x86_64>::addCompressedAddressOffsetFixup(uint32_t offset, const ld::Atom* func, const ld::Atom* fromFunc)
+{
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of3, ld::Fixup::kindSetTargetAddress, func));
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of3, ld::Fixup::kindSubtractTargetAddress, fromFunc));
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndianLow24of32));
+}
+
+template <>
+void UnwindInfoAtom<x86>::addCompressedEncodingFixup(uint32_t offset, const ld::Atom* fde)
+{
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetSectionOffset, fde));
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
+}
+
+template <>
+void UnwindInfoAtom<x86_64>::addCompressedEncodingFixup(uint32_t offset, const ld::Atom* fde)
+{
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetSectionOffset, fde));
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
+}
+
+
+template <>
+void UnwindInfoAtom<x86>::addRegularAddressFixup(uint32_t offset, const ld::Atom* func)
+{
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetImageOffset, func));
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
+}
+
+template <>
+void UnwindInfoAtom<x86_64>::addRegularAddressFixup(uint32_t offset, const ld::Atom* func)
+{
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetImageOffset, func));
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
+}
+
+template <>
+void UnwindInfoAtom<x86>::addRegularFDEOffsetFixup(uint32_t offset, const ld::Atom* fde)
+{
+       _fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k1of2, ld::Fixup::kindSetTargetSectionOffset, fde));
+       _fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
+}
+
+template <>
+void UnwindInfoAtom<x86_64>::addRegularFDEOffsetFixup(uint32_t offset, const ld::Atom* fde)
+{
+       _fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k1of2, ld::Fixup::kindSetTargetSectionOffset, fde));
+       _fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
+}
+
+template <>
+void UnwindInfoAtom<x86>::addImageOffsetFixup(uint32_t offset, const ld::Atom* targ)
+{
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetImageOffset, targ));
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
+}
+
+template <>
+void UnwindInfoAtom<x86_64>::addImageOffsetFixup(uint32_t offset, const ld::Atom* targ)
+{
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetImageOffset, targ));
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
+}
+
+template <>
+void UnwindInfoAtom<x86>::addImageOffsetFixupPlusAddend(uint32_t offset, const ld::Atom* targ, uint32_t addend)
+{
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of3, ld::Fixup::kindSetTargetImageOffset, targ));
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of3, ld::Fixup::kindAddAddend, addend));
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndian32));
+}
+
+template <>
+void UnwindInfoAtom<x86_64>::addImageOffsetFixupPlusAddend(uint32_t offset, const ld::Atom* targ, uint32_t addend)
+{
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of3, ld::Fixup::kindSetTargetImageOffset, targ));
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of3, ld::Fixup::kindAddAddend, addend));
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndian32));
+}
+
+
+
+
+
+template <typename A>
+unsigned int UnwindInfoAtom<A>::makeRegularSecondLevelPage(const std::vector<UnwindEntry>& uniqueInfos, uint32_t pageSize,  
+                                                                                                                       unsigned int endIndex, uint8_t*& pageEnd)
+{
+       const unsigned int maxEntriesPerPage = (pageSize - sizeof(unwind_info_regular_second_level_page_header))/sizeof(unwind_info_regular_second_level_entry);
+       const unsigned int entriesToAdd = ((endIndex > maxEntriesPerPage) ? maxEntriesPerPage : endIndex);
+       uint8_t* pageStart = pageEnd 
+                                               - entriesToAdd*sizeof(unwind_info_regular_second_level_entry) 
+                                               - sizeof(unwind_info_regular_second_level_page_header);
+       macho_unwind_info_regular_second_level_page_header<P>* page = (macho_unwind_info_regular_second_level_page_header<P>*)pageStart;
+       page->set_kind(UNWIND_SECOND_LEVEL_REGULAR);
+       page->set_entryPageOffset(sizeof(macho_unwind_info_regular_second_level_page_header<P>));
+       page->set_entryCount(entriesToAdd);
+       macho_unwind_info_regular_second_level_entry<P>* entryTable = (macho_unwind_info_regular_second_level_entry<P>*)(pageStart + page->entryPageOffset());
+       for (unsigned int i=0; i < entriesToAdd; ++i) {
+               const UnwindEntry& info = uniqueInfos[endIndex-entriesToAdd+i];
+               entryTable[i].set_functionOffset(0);
+               entryTable[i].set_encoding(info.encoding);
+               // add fixup for address part of entry
+               uint32_t offset = (uint8_t*)(&entryTable[i]) - _pagesForDelete;
+               this->addRegularAddressFixup(offset, info.func);
+               if ( encodingMeansUseDwarf(info.encoding) ) {
+                       // add fixup for dwarf offset part of page specific encoding
+                       uint32_t encOffset = (uint8_t*)(&entryTable[i]) - _pagesForDelete;
+                       this->addRegularFDEOffsetFixup(encOffset, info.fde);
+               }
+       }
+       if (_s_log) fprintf(stderr, "regular page with %u entries\n", entriesToAdd);
+       pageEnd = pageStart;
+       return endIndex - entriesToAdd;
+}
+
+
+template <typename A>
+unsigned int UnwindInfoAtom<A>::makeCompressedSecondLevelPage(const std::vector<UnwindEntry>& uniqueInfos,   
+                                                                                                       const std::map<compact_unwind_encoding_t,unsigned int> commonEncodings,  
+                                                                                                       uint32_t pageSize, unsigned int endIndex, uint8_t*& pageEnd)
+{
+       if (_s_log) fprintf(stderr, "makeCompressedSecondLevelPage(pageSize=%u, endIndex=%u)\n", pageSize, endIndex);
+       // first pass calculates how many compressed entries we could fit in this sized page
+       // keep adding entries to page until:
+       //  1) encoding table plus entry table plus header exceed page size
+       //  2) the file offset delta from the first to last function > 24 bits
+       //  3) custom encoding index reachs 255
+       //  4) run out of uniqueInfos to encode
+       std::map<compact_unwind_encoding_t, unsigned int> pageSpecificEncodings;
+       uint32_t space4 =  (pageSize - sizeof(unwind_info_compressed_second_level_page_header))/sizeof(uint32_t);
+       std::vector<uint8_t> encodingIndexes;
+       int index = endIndex-1;
+       int entryCount = 0;
+       uint64_t lastEntryAddress = uniqueInfos[index].funcTentAddress;
+       bool canDo = true;
+       while ( canDo && (index >= 0) ) {
+               const UnwindEntry& info = uniqueInfos[index--];
+               // compute encoding index
+               unsigned int encodingIndex;
+               std::map<compact_unwind_encoding_t, unsigned int>::const_iterator pos = commonEncodings.find(info.encoding);
+               if ( pos != commonEncodings.end() ) {
+                       encodingIndex = pos->second;
+               }
+               else {
+                       // no commmon entry, so add one on this page
+                       uint32_t encoding = info.encoding;
+                       if ( encodingMeansUseDwarf(encoding) ) {
+                               // make unique pseudo encoding so this dwarf will gets is own encoding entry slot
+                               encoding += (index+1);
+                       }
+                       std::map<compact_unwind_encoding_t, unsigned int>::iterator ppos = pageSpecificEncodings.find(encoding);
+                       if ( ppos != pageSpecificEncodings.end() ) {
+                               encodingIndex = pos->second;
+                       }
+                       else {
+                               encodingIndex = commonEncodings.size() + pageSpecificEncodings.size();
+                               if ( encodingIndex <= 255 ) {
+                                       pageSpecificEncodings[encoding] = encodingIndex;
+                               }
+                               else {
+                                       canDo = false; // case 3)
+                                       if (_s_log) fprintf(stderr, "end of compressed page with %u entries, %lu custom encodings because too many custom encodings\n", 
+                                                                                       entryCount, pageSpecificEncodings.size());
+                               }
+                       }
+               }
+               if ( canDo ) 
+                       encodingIndexes.push_back(encodingIndex);
+               // compute function offset
+               uint32_t funcOffsetWithInPage = lastEntryAddress - info.funcTentAddress;
+               if ( funcOffsetWithInPage > 0x00FFFF00 ) {
+                       // don't use 0x00FFFFFF because addresses may vary after atoms are laid out again
+                       canDo = false; // case 2)
+                       if (_s_log) fprintf(stderr, "can't use compressed page with %u entries because function offset too big\n", entryCount);
+               }
+               else {
+                       ++entryCount;
+               }
+               // check room for entry
+               if ( (pageSpecificEncodings.size()+entryCount) >= space4 ) {
+                       canDo = false; // case 1)
+                       --entryCount;
+                       if (_s_log) fprintf(stderr, "end of compressed page with %u entries because full\n", entryCount);
+               }
+               //if (_s_log) fprintf(stderr, "space4=%d, pageSpecificEncodings.size()=%ld, entryCount=%d\n", space4, pageSpecificEncodings.size(), entryCount);
+       }
+       
+       // check for cases where it would be better to use a regular (non-compressed) page
+       const unsigned int compressPageUsed = sizeof(unwind_info_compressed_second_level_page_header) 
+                                                               + pageSpecificEncodings.size()*sizeof(uint32_t)
+                                                               + entryCount*sizeof(uint32_t);
+       if ( (compressPageUsed < (pageSize-4) && (index >= 0) ) ) {
+               const int regularEntriesPerPage = (pageSize - sizeof(unwind_info_regular_second_level_page_header))/sizeof(unwind_info_regular_second_level_entry);
+               if ( entryCount < regularEntriesPerPage ) {
+                       return makeRegularSecondLevelPage(uniqueInfos, pageSize, endIndex, pageEnd);
+               }
+       }
+       
+       // check if we need any padding because adding another entry would take 8 bytes but only have room for 4
+       uint32_t pad = 0;
+       if ( compressPageUsed == (pageSize-4) )
+               pad = 4;
+
+       // second pass fills in page 
+       uint8_t* pageStart = pageEnd - compressPageUsed - pad;
+       CSLP* page = (CSLP*)pageStart;
+       page->set_kind(UNWIND_SECOND_LEVEL_COMPRESSED);
+       page->set_entryPageOffset(sizeof(CSLP));
+       page->set_entryCount(entryCount);
+       page->set_encodingsPageOffset(page->entryPageOffset()+entryCount*sizeof(uint32_t));
+       page->set_encodingsCount(pageSpecificEncodings.size());
+       uint32_t* const encodingsArray = (uint32_t*)&pageStart[page->encodingsPageOffset()];
+       // fill in entry table
+       uint32_t* const entiresArray = (uint32_t*)&pageStart[page->entryPageOffset()];
+       const ld::Atom* firstFunc = uniqueInfos[endIndex-entryCount].func;
+       for(unsigned int i=endIndex-entryCount; i < endIndex; ++i) {
+               const UnwindEntry& info = uniqueInfos[i];
+               uint8_t encodingIndex;
+               if ( encodingMeansUseDwarf(info.encoding) ) {
+                       // dwarf entries are always in page specific encodings
+                       encodingIndex = pageSpecificEncodings[info.encoding+i];
+               }
+               else {
+                       std::map<uint32_t, unsigned int>::const_iterator pos = commonEncodings.find(info.encoding);
+                       if ( pos != commonEncodings.end() ) 
+                               encodingIndex = pos->second;
+                       else 
+                               encodingIndex = pageSpecificEncodings[info.encoding];
+               }
+               uint32_t entryIndex = i - endIndex + entryCount;
+               E::set32(entiresArray[entryIndex], encodingIndex << 24);
+               // add fixup for address part of entry
+               uint32_t offset = (uint8_t*)(&entiresArray[entryIndex]) - _pagesForDelete;
+               this->addCompressedAddressOffsetFixup(offset, info.func, firstFunc);
+               if ( encodingMeansUseDwarf(info.encoding) ) {
+                       // add fixup for dwarf offset part of page specific encoding
+                       uint32_t encOffset = (uint8_t*)(&encodingsArray[encodingIndex-commonEncodings.size()]) - _pagesForDelete;
+                       this->addCompressedEncodingFixup(encOffset, info.fde);
+               }
+       }
+       // fill in encodings table
+       for(std::map<uint32_t, unsigned int>::const_iterator it = pageSpecificEncodings.begin(); it != pageSpecificEncodings.end(); ++it) {
+               E::set32(encodingsArray[it->second-commonEncodings.size()], it->first);
+       }
+       
+       if (_s_log) fprintf(stderr, "compressed page with %u entries, %lu custom encodings\n", entryCount, pageSpecificEncodings.size());
+       
+       // update pageEnd;
+       pageEnd = pageStart;
+       return endIndex-entryCount;  // endIndex for next page
+}
+
+
+
+
+
+
+static uint64_t calculateEHFrameSize(const ld::Internal& state)
+{
+       uint64_t size = 0;
+       for (std::vector<ld::Internal::FinalSection*>::const_iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
+               ld::Internal::FinalSection* sect = *sit;
+               if ( sect->type() == ld::Section::typeCFI ) {
+                       for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+                               size += (*ait)->size();
+                       }
+               }
+       }
+       return size;
+}
+
+static void getAllUnwindInfos(const ld::Internal& state, std::vector<UnwindEntry>& entries)
+{
+       uint64_t address = 0;
+       for (std::vector<ld::Internal::FinalSection*>::const_iterator sit=state.sections.begin(); sit != state.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;
+                       // adjust address for atom alignment
+                       uint64_t alignment = 1 << atom->alignment().powerOf2;
+                       uint64_t currentModulus = (address % alignment);
+                       uint64_t requiredModulus = atom->alignment().modulus;
+                       if ( currentModulus != requiredModulus ) {
+                               if ( requiredModulus > currentModulus )
+                                       address += requiredModulus-currentModulus;
+                               else
+                                       address += requiredModulus+alignment-currentModulus;
+                       }
+
+                       if ( atom->beginUnwind() == atom->endUnwind() ) {
+                               // be sure to mark that we have no unwind info for stuff in the TEXT segment without unwind info
+                               if ( atom->section().type() == ld::Section::typeCode ) {
+                                       entries.push_back(UnwindEntry(atom, address, 0, NULL, NULL, NULL, 0));
+                               }
+                       }
+                       else {
+                               // atom has unwind info(s), add entry for each
+                               const ld::Atom* fde = NULL;
+                               const ld::Atom* lsda = NULL; 
+                               const ld::Atom* personalityPointer = NULL; 
+                               for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+                                       switch ( fit->kind ) {
+                                               case ld::Fixup::kindNoneGroupSubordinateFDE:
+                                                       assert(fit->binding == ld::Fixup::bindingDirectlyBound);
+                                                       fde = fit->u.target;
+                                                       break;
+                                               case ld::Fixup::kindNoneGroupSubordinateLSDA:
+                                                       assert(fit->binding == ld::Fixup::bindingDirectlyBound);
+                                                       lsda = fit->u.target;
+                                                       break;
+                                               default:
+                                                       break;
+                                       }
+                               }
+                               if ( fde != NULL ) {
+                                       // find CIE for this FDE
+                                       const ld::Atom* cie = NULL;
+                                       for (ld::Fixup::iterator fit = fde->fixupsBegin(), end=fde->fixupsEnd(); fit != end; ++fit) {
+                                               if ( fit->kind != ld::Fixup::kindSubtractTargetAddress )
+                                                       continue;
+                                               if ( fit->binding != ld::Fixup::bindingDirectlyBound )
+                                                       continue;
+                                               cie = fit->u.target;
+                                               // CIE is only direct subtracted target in FDE
+                                               assert(cie->section().type() == ld::Section::typeCFI);
+                                               break;
+                                       }
+                                       if ( cie != NULL ) {
+                                               // if CIE can have just one fixup - to the personality pointer
+                                               for (ld::Fixup::iterator fit = cie->fixupsBegin(), end=cie->fixupsEnd(); fit != end; ++fit) {
+                                                       if ( fit->kind == ld::Fixup::kindSetTargetAddress ) {
+                                                               switch ( fit->binding ) {
+                                                                       case ld::Fixup::bindingsIndirectlyBound:
+                                                                               personalityPointer = state.indirectBindingTable[fit->u.bindingIndex];
+                                                                               assert(personalityPointer->section().type() == ld::Section::typeNonLazyPointer);
+                                                                               break;
+                                                                       case ld::Fixup::bindingDirectlyBound:
+                                                                               personalityPointer = fit->u.target;
+                                                                               assert(personalityPointer->section().type() == ld::Section::typeNonLazyPointer);
+                                                                               break;
+                                                                       default:
+                                                                               break;
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                               for ( ld::Atom::UnwindInfo::iterator uit = atom->beginUnwind(); uit != atom->endUnwind(); ++uit ) {
+                                       entries.push_back(UnwindEntry(atom, address, uit->startOffset, fde, lsda, personalityPointer, uit->unwindInfo));
+                               }
+                       }
+                       address += atom->size();
+               }
+       }
+}
+
+
+
+
+void doPass(const Options& opts, ld::Internal& state)
+{
+       //const bool log = false;
+       
+       // only make make __unwind_info in final linked images
+       if ( !opts.needsUnwindInfoSection() )
+               return;
+
+       // walk every atom and gets its unwind info
+       std::vector<UnwindEntry> entries;
+       entries.reserve(64);
+       getAllUnwindInfos(state, entries);
+
+       // don't generate an __unwind_info section if there is no code in this linkage unit
+       if ( entries.size() == 0 )
+               return;
+               
+       // calculate size of __eh_frame section, so __unwind_info can go before it and page align
+       uint64_t ehFrameSize = calculateEHFrameSize(state);
+
+       // create atom that contains the whole compact unwind table
+       switch ( opts.architecture() ) {
+               case CPU_TYPE_X86_64:
+                       state.addAtom(*new UnwindInfoAtom<x86_64>(entries, ehFrameSize));
+                       break;
+               case CPU_TYPE_I386:
+                       state.addAtom(*new UnwindInfoAtom<x86>(entries, ehFrameSize));
+                       break;
+               default:
+                       assert(0 && "no compact unwind for arch");
+       }       
+}
+
+
+} // namespace compact_unwind
+} // namespace passes 
+} // namespace ld 
diff --git a/src/ld/passes/compact_unwind.h b/src/ld/passes/compact_unwind.h
new file mode 100644 (file)
index 0000000..c6dc9f5
--- /dev/null
@@ -0,0 +1,45 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#ifndef __COMPACT_UNWIND_H__
+#define __COMPACT_UNWIND_H__
+
+#include "Options.h"
+#include "ld.hpp"
+
+
+namespace ld {
+namespace passes {
+namespace compact_unwind {
+
+// called by linker to add __unwind_info section table 
+extern void doPass(const Options& opts, ld::Internal& internal);
+
+
+} // namespace compact_unwind
+} // namespace passes 
+} // namespace ld 
+
+#endif // __COMPACT_UNWIND_H__
diff --git a/src/ld/passes/dtrace_dof.cpp b/src/ld/passes/dtrace_dof.cpp
new file mode 100644 (file)
index 0000000..f847cc0
--- /dev/null
@@ -0,0 +1,339 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <stdint.h>
+#include <math.h>
+#include <unistd.h>
+#include <dlfcn.h>
+
+#include <vector>
+#include <map>
+#include <ext/hash_map>
+
+#include "ld.hpp"
+#include "dtrace_dof.h"
+
+// prototype for entry point in libdtrace.dylib
+typedef uint8_t* (*createdof_func_t)(cpu_type_t, unsigned int, const char*[], unsigned int, const char*[], const char*[], uint64_t offsetsInDOF[], size_t* size);
+
+
+namespace ld {
+namespace passes {
+namespace dtrace {
+
+class File; // forward reference
+
+class Atom : public ld::Atom {
+public:
+                                                                                       Atom(class File& f, const char* n,  const uint8_t* content, uint64_t sz);
+
+       virtual ld::File*                                               file() const                                    { return (ld::File*)&_file; }
+       virtual bool                                                    translationUnitSource(const char** dir, const char** ) const 
+                                                                                                                                                       { return false; }
+       virtual const char*                                             name() const                                    { return _name; }
+       virtual uint64_t                                                size() const                                    { return _size; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const
+                                                                                                                                                       { memcpy(buffer, _content, _size); }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return &_fixups[0]; }
+       virtual ld::Fixup::iterator                             fixupsEnd() const                               { return &_fixups[_fixups.size()]; }
+
+protected:
+       friend class File;
+       virtual                                                                 ~Atom() {}
+       
+       class File&                                                             _file;
+       const char*                                                             _name;
+       const uint8_t*                                                  _content;
+       uint64_t                                                                _size;
+       mutable std::vector<ld::Fixup>                  _fixups;
+};
+
+
+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 char* symbolName="dof")
+                                                                       : ld::File(pth, 0, ord),
+                                                                         _atom(*this, symbolName, fileContent, fileLength), 
+                                                                         _section(segmentName, sectionName, ld::Section::typeDtraceDOF) { }
+       virtual                                         ~File() {}
+       
+       virtual bool                            forEachAtom(AtomHandler& h) const { h.doAtom(_atom); return true; }
+       virtual bool                            justInTimeforEachAtom(const char* name, AtomHandler&) const { return false; }
+
+       void                                            reserveFixups(unsigned int count) { _atom._fixups.reserve(count); }
+       void                                            addSectionFixup(const ld::Fixup& f) { _atom._fixups.push_back(f); }
+       ld::Atom&                                       atom() { return _atom; }
+private:
+       friend class Atom;
+       
+       Atom                                            _atom;
+       ld::Section                                     _section;
+};
+
+Atom::Atom(File& f, const char* n,  const uint8_t* content, uint64_t sz)
+       : ld::Atom(f._section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+               ld::Atom::scopeTranslationUnit, ld::Atom::typeUnclassified, 
+               symbolTableNotIn, false, false, false, ld::Atom::Alignment(0)), 
+               _file(f), _name(strdup(n)), _content(content), _size(sz) {}
+
+
+
+class CStringEquals
+{
+public:
+       bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+};
+
+struct DTraceProbeInfo {
+       DTraceProbeInfo(const ld::Atom* a, uint32_t o, const char* n) : atom(a), offset(o), probeName(n) {}
+       const ld::Atom*                                 atom;
+       uint32_t                                                offset;
+       const char*                                             probeName;
+};
+typedef __gnu_cxx::hash_map<const char*, std::vector<DTraceProbeInfo>, __gnu_cxx::hash<const char*>, CStringEquals>    ProviderToProbes;
+typedef        __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals>  CStringSet;
+
+
+
+void doPass(const Options& opts, ld::Internal& internal)
+{
+       static bool log = false;
+       
+       // only make __dof section in final linked images
+       if ( opts.outputKind() == Options::kObjectFile )
+               return;
+
+       // scan all atoms looking for dtrace probes
+       std::vector<DTraceProbeInfo>                                    probeSites;
+       std::vector<DTraceProbeInfo>                                    isEnabledSites;
+       std::map<const ld::Atom*,CStringSet>                    atomToDtraceTypes;
+       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::typeCode ) 
+                       continue;
+               for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin();  ait != sect->atoms.end(); ++ait) {
+                       const ld::Atom* atom = *ait;
+                       for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+                               switch ( fit->kind ) {
+                                       case ld::Fixup::kindStoreX86DtraceCallSiteNop:
+                                       case ld::Fixup::kindStorePPCDtraceCallSiteNop:
+                                       case ld::Fixup::kindStoreARMDtraceCallSiteNop:
+                                       case ld::Fixup::kindStoreThumbDtraceCallSiteNop:
+                                               probeSites.push_back(DTraceProbeInfo(atom, fit->offsetInAtom, fit->u.name));
+                                               break;
+                                       case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
+                                       case ld::Fixup::kindStorePPCDtraceIsEnableSiteClear:
+                                       case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear:
+                                       case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
+                                               isEnabledSites.push_back(DTraceProbeInfo(atom, fit->offsetInAtom, fit->u.name));
+                                               break;
+                                       case ld::Fixup::kindDtraceExtra:
+                                               atomToDtraceTypes[atom].insert(fit->u.name);
+                                               break;
+                                       default:
+                                               break;
+                               }
+                       }
+               }
+       }
+
+       // if no probes, we're done
+       if ( (probeSites.size() == 0) && (isEnabledSites.size() == 0) ) 
+               return;
+       
+       ld::Fixup::Kind storeKind = ld::Fixup::kindNone;
+       switch ( opts.architecture() ) {
+               case CPU_TYPE_POWERPC:
+               case CPU_TYPE_POWERPC64:
+                       storeKind = ld::Fixup::kindStoreBigEndian32;
+                       break;
+               case CPU_TYPE_I386:
+               case CPU_TYPE_X86_64:
+               case CPU_TYPE_ARM:
+                       storeKind = ld::Fixup::kindStoreLittleEndian32;
+                       break;
+               default:
+                       throw "unsupported arch for DOF";
+       }
+       
+       // partition probes by provider name
+       // The symbol names looks like:
+       //      "___dtrace_probe$" provider-name "$" probe-name [ "$"... ]
+       //      "___dtrace_isenabled$" provider-name "$" probe-name [ "$"... ]
+       ProviderToProbes providerToProbes;
+       std::vector<DTraceProbeInfo> emptyList;
+       for(std::vector<DTraceProbeInfo>::iterator it = probeSites.begin(); it != probeSites.end(); ++it) {
+               // ignore probes in functions that were coalesed away rdar://problem/5628149
+               if ( it->atom->coalescedAway() )
+                       continue;
+               const char* providerStart = &it->probeName[16];
+               const char* providerEnd = strchr(providerStart, '$');
+               if ( providerEnd != NULL ) {
+                       char providerName[providerEnd-providerStart+1];
+                       strlcpy(providerName, providerStart, providerEnd-providerStart+1);
+                       ProviderToProbes::iterator pos = providerToProbes.find(providerName);
+                       if ( pos == providerToProbes.end() ) {
+                               const char* dup = strdup(providerName);
+                               providerToProbes[dup] = emptyList;
+                       }
+                       providerToProbes[providerName].push_back(*it);
+               }
+       }
+       for(std::vector<DTraceProbeInfo>::iterator it = isEnabledSites.begin(); it != isEnabledSites.end(); ++it) {
+               // ignore probes in functions that were coalesed away rdar://problem/5628149
+               if ( it->atom->coalescedAway() )
+                       continue;
+               const char* providerStart = &it->probeName[20];
+               const char* providerEnd = strchr(providerStart, '$');
+               if ( providerEnd != NULL ) {
+                       char providerName[providerEnd-providerStart+1];
+                       strlcpy(providerName, providerStart, providerEnd-providerStart+1);
+                       ProviderToProbes::iterator pos = providerToProbes.find(providerName);
+                       if ( pos == providerToProbes.end() ) {
+                               const char* dup = strdup(providerName);
+                               providerToProbes[dup] = emptyList;
+                       }
+                       providerToProbes[providerName].push_back(*it);
+               }
+       }
+       
+       // create a DOF section for each provider
+       int dofIndex=1;
+       CStringSet sectionNamesUsed;
+       for(ProviderToProbes::iterator pit = providerToProbes.begin(); pit != providerToProbes.end(); ++pit, ++dofIndex) {
+               const char* providerName = pit->first;
+               const std::vector<DTraceProbeInfo>& probes = pit->second;
+
+               // open library and find dtrace_create_dof()
+               void* handle = dlopen("/usr/lib/libdtrace.dylib", RTLD_LAZY);
+               if ( handle == NULL )
+                       throwf("couldn't dlopen() /usr/lib/libdtrace.dylib: %s", dlerror());
+               createdof_func_t pCreateDOF = (createdof_func_t)dlsym(handle, "dtrace_ld_create_dof");
+               if ( pCreateDOF == NULL )
+                       throwf("couldn't find \"dtrace_ld_create_dof\" in /usr/lib/libdtrace.dylib: %s", dlerror());
+               // build list of typedefs/stability infos for this provider
+               CStringSet types;
+               for(std::vector<DTraceProbeInfo>::const_iterator it = probes.begin(); it != probes.end(); ++it) {
+                       std::map<const ld::Atom*,CStringSet>::iterator pos = atomToDtraceTypes.find(it->atom);
+                       if ( pos != atomToDtraceTypes.end() ) {
+                               for(CStringSet::iterator sit = pos->second.begin(); sit != pos->second.end(); ++sit) {
+                                       const char* providerStart = strchr(*sit, '$')+1;
+                                       const char* providerEnd = strchr(providerStart, '$');
+                                       if ( providerEnd != NULL ) {
+                                               char aProviderName[providerEnd-providerStart+1];
+                                               strlcpy(aProviderName, providerStart, providerEnd-providerStart+1);
+                                               if ( strcmp(aProviderName, providerName) == 0 )
+                                                       types.insert(*sit);
+                                       }
+                               }
+                       }
+               }
+               int typeCount = types.size();
+               const char* typeNames[typeCount];
+               //fprintf(stderr, "types for %s:\n", providerName);
+               uint32_t index = 0;
+               for(CStringSet::iterator it = types.begin(); it != types.end(); ++it) {
+                       typeNames[index] = *it;
+                       //fprintf(stderr, "\t%s\n", *it);
+                       ++index;
+               }
+               
+               // build list of probe/isenabled sites
+               const uint32_t probeCount = probes.size();
+               const char* probeNames[probeCount];
+               const char* funtionNames[probeCount];
+               uint64_t offsetsInDOF[probeCount];
+               index = 0;
+               for(std::vector<DTraceProbeInfo>::const_iterator it = probes.begin(); it != probes.end(); ++it) {
+                       probeNames[index] = it->probeName;
+                       funtionNames[index] = it->atom->name();
+                       offsetsInDOF[index] = 0;
+                       ++index;
+               }
+               if ( log ) {
+                       fprintf(stderr, "calling libtrace to create DOF:\n");
+                       fprintf(stderr, "   types::\n");
+                       for(int i=0; i < typeCount; ++i) 
+                               fprintf(stderr, "     [%u]\t %s\n", i, typeNames[i]);
+                       fprintf(stderr, "   probes::\n");
+                       for(uint32_t i=0; i < probeCount; ++i) 
+                               fprintf(stderr, "     [%u]\t %s in %s\n", i, probeNames[i], funtionNames[i]);
+               }
+               
+               // call dtrace library to create DOF section
+               size_t dofSectionSize;
+               uint8_t* p = (*pCreateDOF)(opts.architecture(), typeCount, typeNames, probeCount, probeNames, funtionNames, offsetsInDOF, &dofSectionSize);
+               if ( p != NULL ) {
+                       char* sectionName = new char[18]; // alloc new string, pass ownership to File()
+                       strcpy(sectionName, "__dof_");
+                       strlcpy(&sectionName[6], providerName, 10);
+                       // create unique section name so each DOF is in its own section
+                       if ( sectionNamesUsed.count(sectionName) != 0 ) {
+                               sectionName[15] = '0';
+                               sectionName[16] = '\0';
+                               while ( sectionNamesUsed.count(sectionName) != 0 ) {
+                                       ++sectionName[15];
+                               }
+                       }
+                       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);
+                       if ( log ) {
+                               fprintf(stderr, "libdtrace created DOF of size %ld\n", dofSectionSize);
+                       }
+                       // add references
+                       f->reserveFixups(3*probeCount);
+                       for (uint32_t i=0; i < probeCount; ++i) {
+                               uint64_t offset = offsetsInDOF[i];
+                               //fprintf(stderr, "%s offset[%d]=0x%08llX\n", providerName, i, offset);
+                               if ( offset > dofSectionSize )
+                                       throwf("offsetsInDOF[%d]=%0llX > dofSectionSize=%0lX\n", i, offset, dofSectionSize);
+                               f->addSectionFixup(ld::Fixup(offset, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, probes[i].atom));
+                               f->addSectionFixup(ld::Fixup(offset, ld::Fixup::k2of4, ld::Fixup::kindAddAddend, probes[i].offset));
+                               f->addSectionFixup(ld::Fixup(offset, ld::Fixup::k3of4, ld::Fixup::kindSubtractTargetAddress, &f->atom()));
+                               f->addSectionFixup(ld::Fixup(offset, ld::Fixup::k4of4, storeKind));
+                       }
+                       // insert new section
+                       internal.addAtom(f->atom());
+               }
+               else {
+                       throw "error creating dtrace DOF section";
+               }
+       }
+       
+
+
+}
+
+
+} // namespace dtrace
+} // namespace passes 
+} // namespace ld 
diff --git a/src/ld/passes/dtrace_dof.h b/src/ld/passes/dtrace_dof.h
new file mode 100644 (file)
index 0000000..df69b87
--- /dev/null
@@ -0,0 +1,45 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#ifndef __DTRACE_DOF_H__
+#define __DTRACE_DOF_H__
+
+#include "Options.h"
+#include "ld.hpp"
+
+
+namespace ld {
+namespace passes {
+namespace dtrace {
+
+// called by linker to process atoms in Internal and add DOF sections as needed
+extern void doPass(const Options& opts, ld::Internal& internal);
+
+
+} // namespace dtrace
+} // namespace passes 
+} // namespace ld 
+
+#endif // __DTRACE_DOF_H__
diff --git a/src/ld/passes/dylibs.cpp b/src/ld/passes/dylibs.cpp
new file mode 100644 (file)
index 0000000..2b4452b
--- /dev/null
@@ -0,0 +1,86 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <stdint.h>
+#include <math.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <mach/machine.h>
+
+#include <vector>
+
+#include "ld.hpp"
+#include "dylibs.h"
+
+namespace ld {
+namespace passes {
+namespace dylibs {
+
+
+class WillBeUsed
+{
+public:
+       bool operator()(ld::dylib::File* dylib) const {
+               return dylib->willRemoved();
+       }
+};
+
+
+void doPass(const Options& opts, ld::Internal& state)
+{
+//     const bool log = false;
+       
+       // only optimize dylibs in final linked images
+       if ( opts.outputKind() == Options::kObjectFile )
+               return;
+
+       // clear "willRemoved" bit on all dylibs
+       for (std::vector<ld::dylib::File*>::iterator it = state.dylibs.begin(); it != state.dylibs.end(); ++it) {
+               ld::dylib::File* aDylib = *it;
+               aDylib->setWillBeRemoved(false);
+       }
+       for (std::vector<ld::dylib::File*>::iterator it = state.dylibs.begin(); it != state.dylibs.end(); ++it) {
+               ld::dylib::File* aDylib = *it;
+               // set "willRemoved" bit on implicit dylibs that did not provide any exports
+               if ( aDylib->implicitlyLinked() && !aDylib->explicitlyLinked() && !aDylib->providedExportAtom() )
+                       aDylib->setWillBeRemoved(true);
+               // set "willRemoved" bit on dead strippable explicit dylibs that did not provide any exports
+               if ( aDylib->explicitlyLinked() && aDylib->deadStrippable() && !aDylib->providedExportAtom() )
+                       aDylib->setWillBeRemoved(true);
+               // set "willRemoved" bit on any unused explicit when -dead_strip_dylibs is used
+               if ( opts.deadStripDylibs() && !aDylib->providedExportAtom() )
+                       aDylib->setWillBeRemoved(true);
+       }
+       
+       
+       // remove unused dylibs
+       state.dylibs.erase(std::remove_if(state.dylibs.begin(), state.dylibs.end(), WillBeUsed()), state.dylibs.end());
+       
+}
+
+
+} // namespace dylibs
+} // namespace passes 
+} // namespace ld 
diff --git a/src/ld/passes/dylibs.h b/src/ld/passes/dylibs.h
new file mode 100644 (file)
index 0000000..3e4db11
--- /dev/null
@@ -0,0 +1,45 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#ifndef __DYLIBS_H__
+#define __DYLIBS_H__
+
+#include "Options.h"
+#include "ld.hpp"
+
+
+namespace ld {
+namespace passes {
+namespace dylibs {
+
+// called by linker to optimize use of dylibs
+extern void doPass(const Options& opts, ld::Internal& internal);
+
+
+} // namespace dylibs
+} // namespace passes 
+} // namespace ld 
+
+#endif // __DYLIBS_H__
diff --git a/src/ld/passes/got.cpp b/src/ld/passes/got.cpp
new file mode 100644 (file)
index 0000000..ff18e00
--- /dev/null
@@ -0,0 +1,276 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <stdint.h>
+#include <math.h>
+#include <unistd.h>
+#include <dlfcn.h>
+
+#include <vector>
+#include <map>
+#include <ext/hash_map>
+
+#include "ld.hpp"
+#include "got.h"
+
+namespace ld {
+namespace passes {
+namespace got {
+
+class File; // forward reference
+
+class GOTEntryAtom : public ld::Atom {
+public:
+                                                                                       GOTEntryAtom(ld::Internal& internal, const ld::Atom* target, bool weakImport)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)), 
+                               _fixup(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64, target),
+                               _target(target)
+                                       { _fixup.weakImport = weakImport; internal.addAtom(*this); }
+
+       virtual const ld::File*                                 file() const                                    { return NULL; }
+       virtual bool                                                    translationUnitSource(const char** dir, const char**) const 
+                                                                                                                                                       { return false; }
+       virtual const char*                                             name() const                                    { return _target->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 &_fixup; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup)[1]; }
+
+private:
+       mutable ld::Fixup                                               _fixup;
+       const ld::Atom*                                                 _target;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section GOTEntryAtom::_s_section("__DATA", "__got", ld::Section::typeNonLazyPointer);
+
+
+static bool gotFixup(const Options& opts, ld::Internal& internal, const ld::Atom* targetOfGOT, const ld::Fixup* fixup, bool* optimizable)
+{
+       switch (fixup->kind) {
+               case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
+                       // start by assuming this can be optimized
+                       *optimizable = true;
+                       // cannot do LEA optimization if target is in another dylib
+                       if ( targetOfGOT->definition() == ld::Atom::definitionProxy ) 
+                               *optimizable = false;
+                       // cannot do LEA optimization if target in __huge section
+                       if ( internal.usingHugeSections && (targetOfGOT->size() > 1024*1024)
+                                                                                       && (   (targetOfGOT->section().type() == ld::Section::typeZeroFill)
+                                                                                               || (targetOfGOT->section().type() == ld::Section::typeTentativeDefs)) ) {
+                               *optimizable = false;
+                       }
+                       if ( targetOfGOT->scope() == ld::Atom::scopeGlobal ) {  
+                               // cannot do LEA optimization if target is weak exported symbol
+                               if ( (targetOfGOT->definition() == ld::Atom::definitionRegular) && (targetOfGOT->combine() == ld::Atom::combineByName) )
+                                       *optimizable = false;
+                               // cannot do LEA optimization if target is interposable
+                               if ( opts.interposable(targetOfGOT->name()) ) 
+                                       *optimizable = false;
+                               // cannot do LEA optimization if target is resolver function
+                               if ( targetOfGOT->contentType() == ld::Atom::typeResolver ) 
+                                       *optimizable = false;
+                               // cannot do LEA optimization for flat-namespace
+                               if ( opts.nameSpace() != Options::kTwoLevelNameSpace ) 
+                                       *optimizable = false;
+                       }
+                       return true;
+               case ld::Fixup::kindStoreX86PCRel32GOT:
+                       *optimizable = false;
+                       return true;
+               default:
+                       break;
+       }
+       
+       return false;
+}
+
+struct AtomByNameSorter
+{
+        bool operator()(const ld::Atom* left, const ld::Atom* right)
+        {
+                 return (strcmp(left->name(), right->name()) < 0);
+        }
+};
+
+void doPass(const Options& opts, ld::Internal& internal)
+{
+       const bool log = false;
+       
+       // only make got section in final linked images
+       if ( opts.outputKind() == Options::kObjectFile )
+               return;
+
+       // walk all atoms and fixups looking for stubable references
+       // don't create stubs inline because that could invalidate the sections walk
+       std::vector<const ld::Atom*> atomsReferencingGOT;
+       std::map<const ld::Atom*,ld::Atom*> gotMap;
+       std::map<const ld::Atom*,bool>          weakImportMap;
+       atomsReferencingGOT.reserve(128);
+       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;
+                       bool atomUsesGOT = false;
+                       const ld::Atom* targetOfGOT = NULL;
+                       for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+                               if ( fit->firstInCluster() ) 
+                                       targetOfGOT = NULL;
+                               switch ( fit->binding ) {
+                                       case ld::Fixup::bindingsIndirectlyBound:
+                                               targetOfGOT = internal.indirectBindingTable[fit->u.bindingIndex];
+                                               break;
+                                       case ld::Fixup::bindingDirectlyBound:
+                                               targetOfGOT = fit->u.target;
+                                               break;
+                    default:
+                        break;   
+                               }
+                               bool optimizable;
+                               if ( !gotFixup(opts, internal, targetOfGOT, fit, &optimizable) )
+                                       continue;
+                               if ( optimizable ) {
+                                       // change from load of GOT entry to lea of target
+                                       if ( log ) fprintf(stderr, "optimized GOT usage in %s to %s\n", atom->name(), targetOfGOT->name());
+                                       switch ( fit->binding ) {
+                                               case ld::Fixup::bindingsIndirectlyBound:
+                                               case ld::Fixup::bindingDirectlyBound:
+                                                       fit->binding = ld::Fixup::bindingDirectlyBound;
+                                                       fit->u.target = targetOfGOT;
+                                                       fit->kind = ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA;
+                                                       break;
+                                               default:
+                                                       assert(0 && "unsupported GOT reference");
+                                                       break;
+                                       }
+                               }
+                               else {
+                                       // remember that we need to use GOT in this function
+                                       if ( log ) fprintf(stderr, "found GOT use in %s to %s\n", atom->name(), targetOfGOT->name());
+                                       if ( !atomUsesGOT ) {
+                                               atomsReferencingGOT.push_back(atom);
+                                               atomUsesGOT = true;
+                                       }
+                                       gotMap[targetOfGOT] = NULL;
+                                       // record weak_import attribute
+                                       std::map<const ld::Atom*,bool>::iterator pos = weakImportMap.find(targetOfGOT);
+                                       if ( pos == weakImportMap.end() ) {
+                                               // target not in weakImportMap, so add
+                                               weakImportMap[targetOfGOT] = fit->weakImport;
+                                               // <rdar://problem/5529626> If only weak_import symbols are used, linker should use LD_LOAD_WEAK_DYLIB
+                                               const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(targetOfGOT->file());
+                                               if ( dylib != NULL ) {
+                                                       if ( fit->weakImport )
+                                                               (const_cast<ld::dylib::File*>(dylib))->setUsingWeakImportedSymbols();
+                                                       else
+                                                               (const_cast<ld::dylib::File*>(dylib))->setUsingNonWeakImportedSymbols();
+                                               }
+                                       }
+                                       else {
+                                               // target in weakImportMap, check for weakness mismatch
+                                               if ( pos->second != fit->weakImport ) {
+                                                       // found mismatch
+                                                       switch ( opts.weakReferenceMismatchTreatment() ) {
+                                                               case Options::kWeakReferenceMismatchError:
+                                                                       throwf("mismatching weak references for symbol: %s", targetOfGOT->name());
+                                                               case Options::kWeakReferenceMismatchWeak:
+                                                                       pos->second = true;
+                                                                       break;
+                                                               case Options::kWeakReferenceMismatchNonWeak:
+                                                                       pos->second = false;
+                                                                       break;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+       
+       // make GOT entries     
+       for (std::map<const ld::Atom*,ld::Atom*>::iterator it = gotMap.begin(); it != gotMap.end(); ++it) {
+               it->second = new GOTEntryAtom(internal, it->first, weakImportMap[it->first]);
+       }
+       
+       // update atoms to use GOT entries
+       for (std::vector<const ld::Atom*>::iterator it=atomsReferencingGOT.begin(); it != atomsReferencingGOT.end(); ++it) {
+               const ld::Atom* atom = *it;
+               const ld::Atom* targetOfGOT = NULL;
+               ld::Fixup::iterator fitThatSetTarget = NULL;
+               for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+                       if ( fit->firstInCluster() ) {
+                               targetOfGOT = NULL;
+                               fitThatSetTarget = NULL;
+                       }
+                       switch ( fit->binding ) {
+                               case ld::Fixup::bindingsIndirectlyBound:
+                                       targetOfGOT = internal.indirectBindingTable[fit->u.bindingIndex];
+                                       fitThatSetTarget = fit;
+                                       break;
+                               case ld::Fixup::bindingDirectlyBound:
+                                       targetOfGOT = fit->u.target;
+                                       fitThatSetTarget = fit;
+                                       break;
+                default:
+                    break;    
+                       }
+                       bool optimizable;
+                       if ( (targetOfGOT == NULL) || !gotFixup(opts, internal, targetOfGOT, fit, &optimizable) )
+                               continue;
+                       if ( !optimizable ) {
+                               // GOT use not optimized away, update to bind to GOT entry
+                               assert(fitThatSetTarget != NULL);
+                               switch ( fitThatSetTarget->binding ) {
+                                       case ld::Fixup::bindingsIndirectlyBound:
+                                       case ld::Fixup::bindingDirectlyBound:
+                                               fitThatSetTarget->binding = ld::Fixup::bindingDirectlyBound;
+                                               fitThatSetTarget->u.target = gotMap[targetOfGOT];
+                                               break;
+                                       default:
+                                               assert(0 && "unsupported GOT reference");
+                                               break;
+                               }
+                       }
+               }
+       }
+       
+       // sort new atoms so links are consistent
+       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::typeNonLazyPointer ) {
+                       std::sort(sect->atoms.begin(), sect->atoms.end(), AtomByNameSorter());
+               }
+       }
+}
+
+
+} // namespace got
+} // namespace passes 
+} // namespace ld 
diff --git a/src/ld/passes/got.h b/src/ld/passes/got.h
new file mode 100644 (file)
index 0000000..7aae0f8
--- /dev/null
@@ -0,0 +1,45 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#ifndef __GOT_H__
+#define __GOT_H__
+
+#include "Options.h"
+#include "ld.hpp"
+
+
+namespace ld {
+namespace passes {
+namespace got {
+
+// called by linker to create GOT entries and optimize GOT loads into LEAs instead
+extern void doPass(const Options& opts, ld::Internal& internal);
+
+
+} // namespace got
+} // namespace passes 
+} // namespace ld 
+
+#endif // __GOT_H__
diff --git a/src/ld/passes/huge.cpp b/src/ld/passes/huge.cpp
new file mode 100644 (file)
index 0000000..932122a
--- /dev/null
@@ -0,0 +1,113 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <stdint.h>
+#include <math.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <mach/machine.h>
+
+#include <vector>
+
+#include "ld.hpp"
+#include "huge.h"
+
+namespace ld {
+namespace passes {
+namespace huge {
+
+class NullAtom
+{
+public:
+       bool operator()(const ld::Atom* atom) const {
+               return (atom == NULL);
+       }
+};
+
+void doPass(const Options& opts, ld::Internal& state)
+{
+       const bool log = false;
+       
+       // only make make __huge section in final linked images
+       if ( opts.outputKind() == Options::kObjectFile )
+               return;
+
+       // only make make __huge section for x86_64
+       if ( opts.architecture() != CPU_TYPE_X86_64 )
+               return;
+
+       // only needed if some (non-linkedit) atoms have an addresss >2GB from base address 
+       state.usingHugeSections = false;
+       uint64_t address = 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::typePageZero )
+                       continue;
+               if ( sect->type() == ld::Section::typeStack )
+                       continue;
+               for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+                       const ld::Atom* atom = *ait;
+                       if ( (address > 0x7FFFFFFFLL) && !sect->isSectionHidden() ) {
+                               state.usingHugeSections = true;
+                               if (log) fprintf(stderr, "atom: %s is >2GB (0x%09llX), so enabling huge mode\n", atom->name(), address);
+                               break;
+                       }
+                       address += atom->size();
+               }
+               if ( state.usingHugeSections )
+                       break;
+       }
+       if ( !state.usingHugeSections )
+               return;
+
+       // move all zero fill atoms that >1MB in size to a new __huge section
+       ld::Internal::FinalSection* hugeSection = state.getFinalSection(ld::Section("__DATA", "__huge", ld::Section::typeZeroFill));
+       for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
+               ld::Internal::FinalSection* sect = *sit;
+               if ( sect == hugeSection )
+                       continue;
+               if ( sect->type() == ld::Section::typeZeroFill ) {
+                       bool movedSome = false;
+                       for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+                               const ld::Atom* atom = *ait;
+                               if ( atom->size() > 1024*1024 ) {
+                                       hugeSection->atoms.push_back(atom);
+                                       if (log) fprintf(stderr, "moved to __huge: %s, size=%llu\n", atom->name(), atom->size());
+                                       *ait = NULL;  // change atom to NULL for later bulk removal
+                                       movedSome = true;
+                               }
+                       }
+                       if ( movedSome ) 
+                               sect->atoms.erase(std::remove_if(sect->atoms.begin(), sect->atoms.end(), NullAtom()), sect->atoms.end());
+               }
+       }
+
+       
+}
+
+
+} // namespace huge
+} // namespace passes 
+} // namespace ld 
diff --git a/src/ld/passes/huge.h b/src/ld/passes/huge.h
new file mode 100644 (file)
index 0000000..77dc43e
--- /dev/null
@@ -0,0 +1,45 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#ifndef __HUGE_H__
+#define __HUGE_H__
+
+#include "Options.h"
+#include "ld.hpp"
+
+
+namespace ld {
+namespace passes {
+namespace huge {
+
+// called by linker to move large zero-fill atoms to the __huge section
+extern void doPass(const Options& opts, ld::Internal& internal);
+
+
+} // namespace huge
+} // namespace passes 
+} // namespace ld 
+
+#endif // __HUGE_H__
diff --git a/src/ld/passes/objc.cpp b/src/ld/passes/objc.cpp
new file mode 100644 (file)
index 0000000..f420b9f
--- /dev/null
@@ -0,0 +1,1174 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <stdint.h>
+#include <math.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <mach/machine.h>
+
+#include <vector>
+#include <map>
+#include <set>
+
+#include "Architectures.hpp"
+#include "MachOFileAbstraction.hpp"
+
+#include "ld.hpp"
+#include "objc.h"
+
+namespace ld {
+namespace passes {
+namespace objc {
+
+
+
+struct objc_image_info  {
+       uint32_t        version;        // initially 0
+       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)
+#define OBJC_IMAGE_SUPPORTS_COMPACTION (1<<4)
+
+
+
+//
+// This class is the 8 byte section containing ObjC flags
+//
+template <typename A>
+class ObjCImageInfoAtom : public ld::Atom {
+public:
+                                                                                       ObjCImageInfoAtom(ld::File::ObjcConstraint objcConstraint, 
+                                                                                                                       bool compaction, bool objcReplacementClasses, bool abi2);
+
+       virtual const ld::File*                                 file() const                                    { return NULL; }
+       virtual bool                                                    translationUnitSource(const char** dir, const char**) const 
+                                                                                                                                                       { return false; }
+       virtual const char*                                             name() const                                    { return "objc image info"; }
+       virtual uint64_t                                                size() const                                    { return sizeof(objc_image_info); }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+               memcpy(buffer, &_content, sizeof(objc_image_info));
+       }
+
+private:       
+       objc_image_info                                                 _content;
+
+       static ld::Section                                              _s_sectionABI1;
+       static ld::Section                                              _s_sectionABI2;
+};
+
+template <typename A> ld::Section ObjCImageInfoAtom<A>::_s_sectionABI1("__OBJC", "__image_info", ld::Section::typeUnclassified);
+template <typename A> ld::Section ObjCImageInfoAtom<A>::_s_sectionABI2("__DATA", "__objc_imageinfo", ld::Section::typeUnclassified);
+
+
+template <typename A>
+ObjCImageInfoAtom<A>::ObjCImageInfoAtom(ld::File::ObjcConstraint objcConstraint, bool compaction, 
+                                                                               bool objcReplacementClasses, 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:
+                       if ( compaction ) 
+                               warning("ignoring -objc_gc_compaction because code not compiled for ObjC garbage collection");
+                       break;
+               case ld::File::objcConstraintRetainReleaseOrGC:
+                       value |= OBJC_IMAGE_SUPPORTS_GC;
+               if ( compaction ) 
+                       value |= OBJC_IMAGE_SUPPORTS_COMPACTION;
+                       break;
+               case ld::File::objcConstraintGC:
+                       value |= OBJC_IMAGE_SUPPORTS_GC | OBJC_IMAGE_REQUIRES_GC;
+                       if ( compaction ) 
+                               value |= OBJC_IMAGE_SUPPORTS_COMPACTION;
+                       break;
+       }
+
+       _content.version = 0;
+       A::P::E::set32(_content.flags, value);
+}
+
+
+
+//
+// This class is for a new Atom which is an ObjC method list created by merging method lists from categories
+//
+template <typename A>
+class MethodListAtom : public ld::Atom {
+public:
+                                                                                       MethodListAtom(ld::Internal& state, const ld::Atom* baseMethodList, bool meta, 
+                                                                                                                       const std::vector<const ld::Atom*>* categories, 
+                                                                                                                       std::set<const ld::Atom*>& deadAtoms);
+
+       virtual const ld::File*                                 file() const                                    { return _file; }
+       virtual bool                                                    translationUnitSource(const char** dir, const char**) const 
+                                                                                                                                                       { return false; }
+       virtual const char*                                             name() const                                    { return "objc merged method list"; }
+       virtual uint64_t                                                size() const                                    { return _methodCount*3*sizeof(pint_t) + 8; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       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[4])), _methodCount);
+       }
+       virtual ld::Fixup::iterator                             fixupsBegin() const     { return (ld::Fixup*)&_fixups[0]; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const   { return (ld::Fixup*)&_fixups[_fixups.size()]; }
+
+private:       
+       typedef typename A::P::uint_t                   pint_t;
+
+       const ld::File*                                                 _file;
+       unsigned int                                                    _methodCount;
+       std::vector<ld::Fixup>                                  _fixups;
+       
+       static ld::Section                                              _s_section;
+};
+
+template <typename A> 
+ld::Section MethodListAtom<A>::_s_section("__DATA", "__objc_const", ld::Section::typeUnclassified);
+
+
+//
+// This class is for a new Atom which is an ObjC protocol list created by merging protocol lists from categories
+//
+template <typename A>
+class ProtocolListAtom : public ld::Atom {
+public:
+                                                                                       ProtocolListAtom(ld::Internal& state, const ld::Atom* baseProtocolList, 
+                                                                                                                       const std::vector<const ld::Atom*>* categories, 
+                                                                                                                       std::set<const ld::Atom*>& deadAtoms);
+
+       virtual const ld::File*                                 file() const                                    { return _file; }
+       virtual bool                                                    translationUnitSource(const char** dir, const char**) const 
+                                                                                                                                                       { return false; }
+       virtual const char*                                             name() const                                    { return "objc merged protocol list"; }
+       virtual uint64_t                                                size() const                                    { return (_protocolCount+1)*sizeof(pint_t); }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+               bzero(buffer, size());
+               A::P::setP(*((pint_t*)(buffer)), _protocolCount);
+       }
+       virtual ld::Fixup::iterator                             fixupsBegin() const     { return (ld::Fixup*)&_fixups[0]; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const   { return (ld::Fixup*)&_fixups[_fixups.size()]; }
+
+private:       
+       typedef typename A::P::uint_t                   pint_t;
+
+       const ld::File*                                                 _file;
+       unsigned int                                                    _protocolCount;
+       std::vector<ld::Fixup>                                  _fixups;
+       
+       static ld::Section                                              _s_section;
+};
+
+template <typename A> 
+ld::Section ProtocolListAtom<A>::_s_section("__DATA", "__objc_const", ld::Section::typeUnclassified);
+
+
+
+//
+// This class is for a new Atom which is an ObjC property list created by merging property lists from categories
+//
+template <typename A>
+class PropertyListAtom : public ld::Atom {
+public:
+                                                                                       PropertyListAtom(ld::Internal& state, const ld::Atom* baseProtocolList, 
+                                                                                                                       const std::vector<const ld::Atom*>* categories, 
+                                                                                                                       std::set<const ld::Atom*>& deadAtoms);
+
+       virtual const ld::File*                                 file() const                                    { return _file; }
+       virtual bool                                                    translationUnitSource(const char** dir, const char**) const 
+                                                                                                                                                       { return false; }
+       virtual const char*                                             name() const                                    { return "objc merged property list"; }
+       virtual uint64_t                                                size() const                                    { return _propertyCount*2*sizeof(pint_t) + 8; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+               bzero(buffer, size());
+               A::P::E::set32(((uint32_t*)(buffer))[0], 2*sizeof(pint_t)); // sizeof(objc_property)
+               A::P::E::set32(((uint32_t*)(buffer))[1], _propertyCount);
+       }
+       virtual ld::Fixup::iterator                             fixupsBegin() const     { return (ld::Fixup*)&_fixups[0]; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const   { return (ld::Fixup*)&_fixups[_fixups.size()]; }
+
+private:       
+       typedef typename A::P::uint_t                   pint_t;
+
+       const ld::File*                                                 _file;
+       unsigned int                                                    _propertyCount;
+       std::vector<ld::Fixup>                                  _fixups;
+       
+       static ld::Section                                              _s_section;
+};
+
+template <typename A> 
+ld::Section PropertyListAtom<A>::_s_section("__DATA", "__objc_const", ld::Section::typeUnclassified);
+
+
+
+
+
+//
+// This class is used to create an Atom that replaces an atom from a .o file that holds a class_ro_t.
+// It is needed because there is no way to add Fixups to an existing atom.
+//
+template <typename A>
+class ClassROOverlayAtom : public ld::Atom {
+public:
+                                                                                       ClassROOverlayAtom(const ld::Atom* classROAtom);
+
+       // overrides of ld::Atom
+       virtual const ld::File*                         file() const            { return _atom->file(); }
+       virtual bool                                            translationUnitSource(const char** dir, const char** nm) const
+                                                                                                                       { return _atom->translationUnitSource(dir, nm); }
+       virtual const char*                                     name() const            { return _atom->name(); }
+       virtual uint64_t                                        size() const            { return _atom->size(); }
+       virtual uint64_t                                        objectAddress() const { return _atom->objectAddress(); }
+       virtual void                                            copyRawContent(uint8_t buffer[]) const 
+                                                                                                                       { _atom->copyRawContent(buffer); }
+       virtual const uint8_t*                          rawContentPointer() const 
+                                                                                                                       { return _atom->rawContentPointer(); }
+       virtual unsigned long                           contentHash(const class ld::IndirectBindingTable& ibt) const 
+                                                                                                                       { return _atom->contentHash(ibt); }
+       virtual bool                                            canCoalesceWith(const ld::Atom& rhs, const class ld::IndirectBindingTable& ibt) const 
+                                                                                                                       { return _atom->canCoalesceWith(rhs,ibt); }
+
+       virtual ld::Fixup::iterator                     fixupsBegin() const     { return (ld::Fixup*)&_fixups[0]; }
+       virtual ld::Fixup::iterator                     fixupsEnd()     const   { return (ld::Fixup*)&_fixups[_fixups.size()]; }
+
+       void                                                            addProtocolListFixup();
+       void                                                            addPropertyListFixup();
+       void                                                            addMethodListFixup();
+
+private:       
+       typedef typename A::P::uint_t                   pint_t;
+
+       const ld::Atom*                                                 _atom;
+       std::vector<ld::Fixup>                                  _fixups;
+};
+
+template <typename A>
+ClassROOverlayAtom<A>::ClassROOverlayAtom(const ld::Atom* classROAtom)
+       : ld::Atom(classROAtom->section(), ld::Atom::definitionRegular, ld::Atom::combineNever,
+                       ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified, 
+                       classROAtom->symbolTableInclusion(), false, false, false, classROAtom->alignment()),
+       _atom(classROAtom)
+{
+       // ensure all attributes are same as original
+       this->setAttributesFromAtom(*classROAtom);
+
+       // copy fixups from orginal atom
+       for (ld::Fixup::iterator fit=classROAtom->fixupsBegin(); fit != classROAtom->fixupsEnd(); ++fit) {
+               ld::Fixup fixup = *fit;
+               _fixups.push_back(fixup);
+       }
+}
+
+
+//
+// Base class for reading and updating existing ObjC atoms from .o files
+//
+template <typename A>
+class ObjCData {
+public:
+       static const ld::Atom*  getPointerInContent(ld::Internal& state, const ld::Atom* contentAtom, unsigned int offset, bool* hasAddend=NULL);
+       static void                             setPointerInContent(ld::Internal& state, const ld::Atom* contentAtom, 
+                                                                                               unsigned int offset, const ld::Atom* newAtom);
+       typedef typename A::P::uint_t                   pint_t;
+};
+
+template <typename A>
+const ld::Atom* ObjCData<A>::getPointerInContent(ld::Internal& state, const ld::Atom* contentAtom, unsigned int offset, bool* hasAddend)
+{
+       const ld::Atom* target = NULL;
+       if ( hasAddend != NULL )
+               *hasAddend = false;
+       for (ld::Fixup::iterator fit=contentAtom->fixupsBegin(); fit != contentAtom->fixupsEnd(); ++fit) {
+               if ( fit->offsetInAtom == offset ) {
+                       switch ( fit->binding ) {
+                               case ld::Fixup::bindingsIndirectlyBound:
+                                       target = state.indirectBindingTable[fit->u.bindingIndex];
+                                       break;
+                               case ld::Fixup::bindingDirectlyBound:
+                                       target =  fit->u.target;
+                                       break;
+                               case ld::Fixup::bindingNone:
+                                       if ( fit->kind == ld::Fixup::kindAddAddend ) {
+                                               if ( hasAddend != NULL )
+                                                       *hasAddend = true;
+                                       }
+                                       break;
+                 default:
+                    break;   
+                       }
+               }
+       }
+       return target;
+}
+
+template <typename A>
+void ObjCData<A>::setPointerInContent(ld::Internal& state, const ld::Atom* contentAtom, 
+                                                                                                               unsigned int offset, const ld::Atom* newAtom)
+{
+       for (ld::Fixup::iterator fit=contentAtom->fixupsBegin(); fit != contentAtom->fixupsEnd(); ++fit) {
+               if ( fit->offsetInAtom == offset ) {
+                       switch ( fit->binding ) {
+                               case ld::Fixup::bindingsIndirectlyBound:
+                                       state.indirectBindingTable[fit->u.bindingIndex] = newAtom;
+                                       return;
+                               case ld::Fixup::bindingDirectlyBound:
+                                       fit->u.target = newAtom;
+                                       return;
+                default:
+                     break;    
+                       }
+               }
+       }
+       assert(0 && "could not update method list");
+}
+
+
+
+//
+// Helper class for reading and updating existing ObjC category atoms from .o files
+//
+template <typename A>
+class Category : public ObjCData<A> {
+public:
+       static const ld::Atom*  getClass(ld::Internal& state, const ld::Atom* contentAtom);
+       static const ld::Atom*  getInstanceMethods(ld::Internal& state, const ld::Atom* contentAtom);
+       static const ld::Atom*  getClassMethods(ld::Internal& state, const ld::Atom* contentAtom);
+       static const ld::Atom*  getProtocols(ld::Internal& state, const ld::Atom* contentAtom);
+       static const ld::Atom*  getProperties(ld::Internal& state, const ld::Atom* contentAtom);
+       static uint32_t         size() { return 6*sizeof(pint_t); }
+private:       
+       typedef typename A::P::uint_t                   pint_t;
+};
+
+
+template <typename A>
+const ld::Atom*        Category<A>::getClass(ld::Internal& state, const ld::Atom* contentAtom)
+{
+       return ObjCData<A>::getPointerInContent(state, contentAtom, sizeof(pint_t)); // category_t.cls
+}
+
+template <typename A>
+const ld::Atom*        Category<A>::getInstanceMethods(ld::Internal& state, const ld::Atom* contentAtom)
+{
+       return ObjCData<A>::getPointerInContent(state, contentAtom, 2*sizeof(pint_t)); // category_t.instanceMethods
+}
+
+template <typename A>
+const ld::Atom*        Category<A>::getClassMethods(ld::Internal& state, const ld::Atom* contentAtom)
+{
+       return ObjCData<A>::getPointerInContent(state, contentAtom, 3*sizeof(pint_t)); // category_t.classMethods
+}
+
+template <typename A>
+const ld::Atom*        Category<A>::getProtocols(ld::Internal& state, const ld::Atom* contentAtom)
+{
+       return ObjCData<A>::getPointerInContent(state, contentAtom, 4*sizeof(pint_t)); // category_t.protocols
+}
+
+template <typename A>
+const ld::Atom*        Category<A>::getProperties(ld::Internal& state, const ld::Atom* contentAtom)
+{
+       return ObjCData<A>::getPointerInContent(state, contentAtom, 5*sizeof(pint_t)); // category_t.instanceProperties
+}
+
+
+template <typename A>
+class MethodList : public ObjCData<A> {
+public:
+       static uint32_t count(ld::Internal& state, const ld::Atom* methodListAtom) {
+               const uint32_t* methodListData = (uint32_t*)(methodListAtom->rawContentPointer());
+               return A::P::E::get32(methodListData[1]); // method_list_t.count
+       }
+};
+
+template <typename A>
+class ProtocolList : public ObjCData<A> {
+public:
+       static uint32_t count(ld::Internal& state, const ld::Atom* protocolListAtom)  {
+               pint_t* protocolListData = (pint_t*)(protocolListAtom->rawContentPointer());
+               return A::P::getP(*protocolListData); // protocol_list_t.count
+       }
+private:
+       typedef typename A::P::uint_t   pint_t;
+};
+
+template <typename A>
+class PropertyList : public ObjCData<A> {
+public:
+       static uint32_t count(ld::Internal& state, const ld::Atom* protocolListAtom)  {
+               uint32_t* protocolListData = (uint32_t*)(protocolListAtom->rawContentPointer());
+               return A::P::E::get32(protocolListData[1]); // property_list_t.count
+       }
+private:
+       typedef typename A::P::uint_t   pint_t;
+};
+
+
+
+//
+// Helper class for reading and updating existing ObjC class atoms from .o files
+//
+template <typename A>
+class Class : public ObjCData<A> {
+public:
+       static const ld::Atom*  getInstanceMethodList(ld::Internal& state, const ld::Atom* classAtom);
+       static const ld::Atom*  getInstanceProtocolList(ld::Internal& state, const ld::Atom* classAtom);
+       static const ld::Atom*  getInstancePropertyList(ld::Internal& state, const ld::Atom* classAtom);
+       static const ld::Atom*  getClassMethodList(ld::Internal& state, const ld::Atom* classAtom);
+       static const ld::Atom*  setInstanceMethodList(ld::Internal& state, const ld::Atom* classAtom, 
+                                                                                               const ld::Atom* methodListAtom, std::set<const ld::Atom*>& deadAtoms);
+       static const ld::Atom*  setInstanceProtocolList(ld::Internal& state, const ld::Atom* classAtom, 
+                                                                                               const ld::Atom* protocolListAtom, std::set<const ld::Atom*>& deadAtoms);
+       static const ld::Atom*  setInstancePropertyList(ld::Internal& state, const ld::Atom* classAtom, 
+                                                                                               const ld::Atom* propertyListAtom, std::set<const ld::Atom*>& deadAtoms);
+       static const ld::Atom*  setClassMethodList(ld::Internal& state, const ld::Atom* classAtom, 
+                                                                                               const ld::Atom* methodListAtom, std::set<const ld::Atom*>& deadAtoms);
+       static const ld::Atom*  setClassProtocolList(ld::Internal& state, const ld::Atom* classAtom, 
+                                                                                               const ld::Atom* protocolListAtom, std::set<const ld::Atom*>& deadAtoms);
+       static uint32_t         size() { return 5*sizeof(pint_t); }
+       static unsigned int             class_ro_header_size();
+private:
+       typedef typename A::P::uint_t                   pint_t;
+       static const ld::Atom*  getROData(ld::Internal& state, const ld::Atom* classAtom);
+};
+
+template <> unsigned int Class<x86_64>::class_ro_header_size() { return 16; }
+template <> unsigned int Class<arm>::class_ro_header_size() { return 12;}
+template <> unsigned int Class<x86>::class_ro_header_size() { return 12; }
+
+
+template <typename A>
+const ld::Atom*        Class<A>::getROData(ld::Internal& state, const ld::Atom* classAtom)
+{
+       return ObjCData<A>::getPointerInContent(state, classAtom, 4*sizeof(pint_t)); // class_t.data
+
+}
+
+template <typename A>
+const ld::Atom*        Class<A>::getInstanceMethodList(ld::Internal& state, const ld::Atom* classAtom)
+{
+       const ld::Atom* classROAtom = getROData(state, classAtom); // class_t.data
+       assert(classROAtom != NULL);
+       return ObjCData<A>::getPointerInContent(state, classROAtom, class_ro_header_size() + 2*sizeof(pint_t)); // class_ro_t.baseMethods
+}
+
+template <typename A>
+const ld::Atom*        Class<A>::getInstanceProtocolList(ld::Internal& state, const ld::Atom* classAtom)
+{
+       const ld::Atom* classROAtom = getROData(state, classAtom); // class_t.data
+       assert(classROAtom != NULL);
+       return ObjCData<A>::getPointerInContent(state, classROAtom, class_ro_header_size() + 3*sizeof(pint_t)); // class_ro_t.baseProtocols
+}
+
+template <typename A>
+const ld::Atom*        Class<A>::getInstancePropertyList(ld::Internal& state, const ld::Atom* classAtom)
+{
+       const ld::Atom* classROAtom = getROData(state, classAtom); // class_t.data
+       assert(classROAtom != NULL);
+       return ObjCData<A>::getPointerInContent(state, classROAtom, class_ro_header_size() + 6*sizeof(pint_t)); // class_ro_t.baseProperties
+}
+
+template <typename A>
+const ld::Atom*        Class<A>::getClassMethodList(ld::Internal& state, const ld::Atom* classAtom)
+{
+       const ld::Atom* metaClassAtom = ObjCData<A>::getPointerInContent(state, classAtom, 0); // class_t.isa
+       assert(metaClassAtom != NULL);
+       return Class<A>::getInstanceMethodList(state, metaClassAtom);
+}
+
+template <typename A>
+const ld::Atom* Class<A>::setInstanceMethodList(ld::Internal& state, const ld::Atom* classAtom, 
+                                                                                               const ld::Atom* methodListAtom, std::set<const ld::Atom*>& deadAtoms)
+{
+       const ld::Atom* classROAtom = getROData(state, classAtom); // class_t.data
+       assert(classROAtom != NULL);
+       // if the base class does not already have a method list, we need to create an overlay
+       if ( getInstanceMethodList(state, classAtom) == NULL ) {
+               ClassROOverlayAtom<A>* overlay = new ClassROOverlayAtom<A>(classROAtom);
+               //fprintf(stderr, "replace class RO atom %p with %p for method list in class atom %s\n", classROAtom, overlay, classAtom->name());
+               overlay->addMethodListFixup();
+               ObjCData<A>::setPointerInContent(state, classAtom, 4*sizeof(pint_t), overlay); // class_t.data
+               deadAtoms.insert(classROAtom);
+               ObjCData<A>::setPointerInContent(state, overlay, class_ro_header_size() + 2*sizeof(pint_t), methodListAtom); // class_ro_t.baseMethods
+               return overlay;
+       }
+       ObjCData<A>::setPointerInContent(state, classROAtom, class_ro_header_size() + 2*sizeof(pint_t), methodListAtom); // class_ro_t.baseMethods
+       return NULL; // means classRO atom was not replaced
+}
+
+template <typename A>
+const ld::Atom* Class<A>::setInstanceProtocolList(ld::Internal& state, const ld::Atom* classAtom, 
+                                                                       const ld::Atom* protocolListAtom, std::set<const ld::Atom*>& deadAtoms)
+{
+       const ld::Atom* classROAtom = getROData(state, classAtom); // class_t.data
+       assert(classROAtom != NULL);
+       // if the base class does not already have a protocol list, we need to create an overlay
+       if ( getInstanceProtocolList(state, classAtom) == NULL ) {
+               ClassROOverlayAtom<A>* overlay = new ClassROOverlayAtom<A>(classROAtom);
+               //fprintf(stderr, "replace class RO atom %p with %p for protocol list in class atom %s\n", classROAtom, overlay, classAtom->name());
+               overlay->addProtocolListFixup();
+               ObjCData<A>::setPointerInContent(state, classAtom, 4*sizeof(pint_t), overlay); // class_t.data
+               deadAtoms.insert(classROAtom);
+               ObjCData<A>::setPointerInContent(state, overlay, class_ro_header_size() + 3*sizeof(pint_t), protocolListAtom); // class_ro_t.baseProtocols
+               return overlay;
+       }
+       //fprintf(stderr, "set class RO atom %p protocol list in class atom %s\n", classROAtom, classAtom->name());
+       ObjCData<A>::setPointerInContent(state, classROAtom, class_ro_header_size() + 3*sizeof(pint_t), protocolListAtom); // class_ro_t.baseProtocols
+       return NULL;  // means classRO atom was not replaced
+}
+
+template <typename A>
+const ld::Atom* Class<A>::setClassProtocolList(ld::Internal& state, const ld::Atom* classAtom, 
+                                                                       const ld::Atom* protocolListAtom, std::set<const ld::Atom*>& deadAtoms)
+{
+       // meta class also points to same protocol list as class
+       const ld::Atom* metaClassAtom = ObjCData<A>::getPointerInContent(state, classAtom, 0); // class_t.isa
+       //fprintf(stderr, "setClassProtocolList(), classAtom=%p %s, metaClass=%p %s\n", classAtom, classAtom->name(), metaClassAtom, metaClassAtom->name());
+       assert(metaClassAtom != NULL);
+       return setInstanceProtocolList(state, metaClassAtom, protocolListAtom, deadAtoms);
+}
+
+
+
+template <typename A>
+const ld::Atom*  Class<A>::setInstancePropertyList(ld::Internal& state, const ld::Atom* classAtom, 
+                                                                                               const ld::Atom* propertyListAtom, std::set<const ld::Atom*>& deadAtoms)
+{
+       const ld::Atom* classROAtom = getROData(state, classAtom); // class_t.data
+       assert(classROAtom != NULL);
+       // if the base class does not already have a property list, we need to create an overlay
+       if ( getInstancePropertyList(state, classAtom) == NULL ) {
+               ClassROOverlayAtom<A>* overlay = new ClassROOverlayAtom<A>(classROAtom);
+               //fprintf(stderr, "replace class RO atom %p with %p for property list in class atom %s\n", classROAtom, overlay, classAtom->name());
+               overlay->addPropertyListFixup();
+               ObjCData<A>::setPointerInContent(state, classAtom, 4*sizeof(pint_t), overlay); // class_t.data
+               deadAtoms.insert(classROAtom);
+               ObjCData<A>::setPointerInContent(state, overlay, class_ro_header_size() + 6*sizeof(pint_t), propertyListAtom); // class_ro_t.baseProperties
+               return overlay;
+       }
+       ObjCData<A>::setPointerInContent(state, classROAtom, class_ro_header_size() + 6*sizeof(pint_t), propertyListAtom); // class_ro_t.baseProperties
+       return NULL;  // means classRO atom was not replaced
+}
+
+template <typename A>
+const ld::Atom* Class<A>::setClassMethodList(ld::Internal& state, const ld::Atom* classAtom, 
+                                                                                       const ld::Atom* methodListAtom, std::set<const ld::Atom*>& deadAtoms)
+{
+       // class methods is just instance methods of metaClass
+       const ld::Atom* metaClassAtom = ObjCData<A>::getPointerInContent(state, classAtom, 0); // class_t.isa
+       assert(metaClassAtom != NULL);
+       return setInstanceMethodList(state, metaClassAtom, methodListAtom, deadAtoms);
+}
+
+
+
+template <>
+void ClassROOverlayAtom<x86_64>::addMethodListFixup()
+{
+       const ld::Atom* targetAtom = this; // temporary
+       uint32_t offset = Class<x86_64>::class_ro_header_size() + 2*8; // class_ro_t.baseMethods
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64, targetAtom));
+}
+
+template <>
+void ClassROOverlayAtom<arm>::addMethodListFixup()
+{
+       const ld::Atom* targetAtom = this; // temporary
+       uint32_t offset = Class<arm>::class_ro_header_size() + 2*4; // class_ro_t.baseMethods
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, targetAtom));
+}
+
+template <>
+void ClassROOverlayAtom<x86>::addMethodListFixup()
+{
+       const ld::Atom* targetAtom = this; // temporary
+       uint32_t offset = Class<x86>::class_ro_header_size() + 2*4; // class_ro_t.baseMethods
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, targetAtom));
+}
+
+
+
+template <>
+void ClassROOverlayAtom<x86_64>::addProtocolListFixup()
+{
+       const ld::Atom* targetAtom = this; // temporary
+       uint32_t offset = Class<x86_64>::class_ro_header_size() + 3*8; // class_ro_t.baseProtocols
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64, targetAtom));
+}
+
+template <>
+void ClassROOverlayAtom<arm>::addProtocolListFixup()
+{
+       const ld::Atom* targetAtom = this; // temporary
+       uint32_t offset = Class<arm>::class_ro_header_size() + 3*4; // class_ro_t.baseProtocols
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, targetAtom));
+}
+
+template <>
+void ClassROOverlayAtom<x86>::addProtocolListFixup()
+{
+       const ld::Atom* targetAtom = this; // temporary
+       uint32_t offset = Class<x86>::class_ro_header_size() + 3*4; // class_ro_t.baseProtocols
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, targetAtom));
+}
+
+
+template <>
+void ClassROOverlayAtom<x86_64>::addPropertyListFixup()
+{
+       const ld::Atom* targetAtom = this; // temporary
+       uint32_t offset = Class<x86_64>::class_ro_header_size() + 6*8; // class_ro_t.baseProperties
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64, targetAtom));
+}
+
+template <>
+void ClassROOverlayAtom<arm>::addPropertyListFixup()
+{
+       const ld::Atom* targetAtom = this; // temporary
+       uint32_t offset = Class<arm>::class_ro_header_size() + 6*4; // class_ro_t.baseProperties
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, targetAtom));
+}
+
+template <>
+void ClassROOverlayAtom<x86>::addPropertyListFixup()
+{
+       const ld::Atom* targetAtom = this; // temporary
+       uint32_t offset = Class<x86>::class_ro_header_size() + 6*4; // class_ro_t.baseProperties
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, targetAtom));
+}
+
+
+
+
+//
+// Encapsulates merging of ObjC categories
+//
+template <typename A>
+class OptimizeCategories {
+public:
+       static void                             doit(const Options& opts, ld::Internal& state);
+       static bool                             hasInstanceMethods(ld::Internal& state, const std::vector<const ld::Atom*>* categories);
+       static bool                             hasClassMethods(ld::Internal& state, const std::vector<const ld::Atom*>* categories);
+       static bool                             hasProtocols(ld::Internal& state, const std::vector<const ld::Atom*>* categories);
+       static bool                             hasProperties(ld::Internal& state, const std::vector<const ld::Atom*>* categories);
+       
+       
+       static unsigned int             class_ro_baseMethods_offset();
+private:
+       typedef typename A::P::uint_t                   pint_t;
+
+};
+
+
+template <typename A>
+bool OptimizeCategories<A>::hasInstanceMethods(ld::Internal& state, const std::vector<const ld::Atom*>* categories)
+{
+       for (std::vector<const ld::Atom*>::const_iterator it=categories->begin(); it != categories->end(); ++it) {
+               const ld::Atom* categoryAtom = *it;
+               const ld::Atom* methodList = Category<A>::getInstanceMethods(state, categoryAtom);
+               if ( methodList != NULL ) {
+                       if ( MethodList<A>::count(state, methodList) > 0 )
+                               return true;
+               }
+       }
+       return false;
+}
+
+
+template <typename A>
+bool OptimizeCategories<A>::hasClassMethods(ld::Internal& state, const std::vector<const ld::Atom*>* categories)
+{
+       for (std::vector<const ld::Atom*>::const_iterator it=categories->begin(); it != categories->end(); ++it) {
+               const ld::Atom* categoryAtom = *it;
+               const ld::Atom* methodList = Category<A>::getClassMethods(state, categoryAtom);
+               if ( methodList != NULL ) {
+                       if ( MethodList<A>::count(state, methodList) > 0 )
+                               return true;
+               }
+       }
+       return false;
+}
+
+template <typename A>
+bool OptimizeCategories<A>::hasProtocols(ld::Internal& state, const std::vector<const ld::Atom*>* categories)
+{
+       for (std::vector<const ld::Atom*>::const_iterator it=categories->begin(); it != categories->end(); ++it) {
+               const ld::Atom* categoryAtom = *it;
+               const ld::Atom* protocolListAtom = Category<A>::getProtocols(state, categoryAtom);
+               if ( protocolListAtom != NULL ) {
+                       if ( ProtocolList<A>::count(state, protocolListAtom) > 0 ) {    
+                               return true;
+                       }
+               }
+       }
+       return false;
+}
+
+
+template <typename A>
+bool OptimizeCategories<A>::hasProperties(ld::Internal& state, const std::vector<const ld::Atom*>* categories)
+{
+       for (std::vector<const ld::Atom*>::const_iterator it=categories->begin(); it != categories->end(); ++it) {
+               const ld::Atom* categoryAtom = *it;
+               const ld::Atom* propertyListAtom = Category<A>::getProperties(state, categoryAtom);
+               if ( propertyListAtom != NULL ) {
+                       if ( PropertyList<A>::count(state, propertyListAtom) > 0 )
+                               return true;
+               }
+       }
+       return false;
+}
+
+
+
+//
+// Helper for std::remove_if
+//
+class OptimizedAway {
+public:
+       OptimizedAway(const std::set<const ld::Atom*>& oa) : _dead(oa) {}
+       bool operator()(const ld::Atom* atom) const {
+               return ( _dead.count(atom) != 0 );
+       }
+private:
+       const std::set<const ld::Atom*>& _dead;
+};
+
+template <typename A>
+void OptimizeCategories<A>::doit(const Options& opts, ld::Internal& state)
+{
+       // first find all categories referenced by __objc_nlcatlist section
+       std::set<const ld::Atom*> nlcatListAtoms;
+       for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
+               ld::Internal::FinalSection* sect = *sit;
+               if ( (strcmp(sect->sectionName(), "__objc_nlcatlist") == 0) && (strcmp(sect->segmentName(), "__DATA") == 0) ) {
+                       for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+                               const ld::Atom* categoryListElementAtom = *ait;
+                               for (unsigned int offset=0; offset < categoryListElementAtom->size(); offset += sizeof(pint_t)) {
+                                       const ld::Atom* categoryAtom = ObjCData<A>::getPointerInContent(state, categoryListElementAtom, offset);
+                                       //fprintf(stderr, "offset=%d, cat=%p %s\n", offset, categoryAtom, categoryAtom->name());
+                                       assert(categoryAtom != NULL);
+                                       nlcatListAtoms.insert(categoryAtom);
+                               }
+                       }
+               }
+       }
+       
+       // 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::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) {
+               ld::Internal::FinalSection* sect = *sit;
+               if ( sect->type() == ld::Section::typeObjC2CategoryList ) {
+                       for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+                               const ld::Atom* categoryListElementAtom = *ait;
+                               bool hasAddend;
+                               const ld::Atom* categoryAtom = ObjCData<A>::getPointerInContent(state, categoryListElementAtom, 0, &hasAddend);
+                               if ( hasAddend || (categoryAtom->symbolTableInclusion() ==  ld::Atom::symbolTableNotIn)) {
+                                       //<rdar://problem/8309530> gcc-4.0 uses 'L' labels on categories which disables this optimization
+                                       //warning("__objc_catlist element does not point to start of category");
+                                       continue;
+                               }
+                               assert(categoryAtom != NULL);
+                               assert(categoryAtom->size() == Category<A>::size());
+                               // ignore categories also in __objc_nlcatlist
+                               if ( nlcatListAtoms.count(categoryAtom) != 0 )
+                                       continue;
+                               const ld::Atom* categoryOnClassAtom = Category<A>::getClass(state, categoryAtom); 
+                               assert(categoryOnClassAtom != NULL);
+                               if ( categoryOnClassAtom->definition() != ld::Atom::definitionProxy ) {
+                                       // only look at classes defined in this image
+                                       CatMap::iterator pos = classToCategories.find(categoryOnClassAtom);
+                                       if ( pos == classToCategories.end() ) {
+                                               classToCategories[categoryOnClassAtom] = new std::vector<const ld::Atom*>();
+                                       }
+                                       classToCategories[categoryOnClassAtom]->push_back(categoryAtom);
+                                       // mark category atom and catlist atom as dead
+                                       deadAtoms.insert(categoryAtom);
+                                       deadAtoms.insert(categoryListElementAtom);
+                               }
+                       }
+               }
+               // record method list section
+               if ( (strcmp(sect->sectionName(), "__objc_const") == 0) && (strcmp(sect->segmentName(), "__DATA") == 0) )
+                       methodListSection = sect;
+       }
+
+       // if found some categories
+       if ( classToCategories.size() != 0 ) {
+               assert(methodListSection != NULL);
+               // 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;
+                       assert(categories->size() != 0);
+                       // if any category adds instance methods, generate new merged method list, and replace
+                       if ( OptimizeCategories<A>::hasInstanceMethods(state, categories) ) { 
+                               const ld::Atom* baseInstanceMethodListAtom = Class<A>::getInstanceMethodList(state, classAtom); 
+                               const ld::Atom* newInstanceMethodListAtom = new MethodListAtom<A>(state, baseInstanceMethodListAtom, false, categories, deadAtoms);
+                               const ld::Atom* newClassRO = Class<A>::setInstanceMethodList(state, classAtom, newInstanceMethodListAtom, deadAtoms);
+                               // add new method list to final sections
+                               methodListSection->atoms.push_back(newInstanceMethodListAtom);
+                               if ( newClassRO != NULL ) {
+                                       assert(strcmp(newClassRO->section().sectionName(), "__objc_const") == 0);
+                                       methodListSection->atoms.push_back(newClassRO);
+                               }
+                       }
+                       // if any category adds class methods, generate new merged method list, and replace
+                       if ( OptimizeCategories<A>::hasClassMethods(state, categories) ) { 
+                               const ld::Atom* baseClassMethodListAtom = Class<A>::getClassMethodList(state, classAtom); 
+                               const ld::Atom* newClassMethodListAtom = new MethodListAtom<A>(state, baseClassMethodListAtom, true, categories, deadAtoms);
+                               const ld::Atom* newClassRO = Class<A>::setClassMethodList(state, classAtom, newClassMethodListAtom, deadAtoms);
+                               // add new method list to final sections
+                               methodListSection->atoms.push_back(newClassMethodListAtom);
+                               if ( newClassRO != NULL ) {
+                                       assert(strcmp(newClassRO->section().sectionName(), "__objc_const") == 0);
+                                       methodListSection->atoms.push_back(newClassRO);
+                               }
+                       }
+                       // if any category adds protocols, generate new merged protocol list, and replace
+                       if ( OptimizeCategories<A>::hasProtocols(state, categories) ) { 
+                               const ld::Atom* baseProtocolListAtom = Class<A>::getInstanceProtocolList(state, classAtom); 
+                               const ld::Atom* newProtocolListAtom = new ProtocolListAtom<A>(state, baseProtocolListAtom, categories, deadAtoms);
+                               const ld::Atom* newClassRO = Class<A>::setInstanceProtocolList(state, classAtom, newProtocolListAtom, deadAtoms);
+                               const ld::Atom* newMetaClassRO = Class<A>::setClassProtocolList(state, classAtom, newProtocolListAtom, deadAtoms);
+                               // add new protocol list to final sections
+                               methodListSection->atoms.push_back(newProtocolListAtom);
+                               if ( newClassRO != NULL ) {
+                                       assert(strcmp(newClassRO->section().sectionName(), "__objc_const") == 0);
+                                       methodListSection->atoms.push_back(newClassRO);
+                               }
+                               if ( newMetaClassRO != NULL ) {
+                                       assert(strcmp(newMetaClassRO->section().sectionName(), "__objc_const") == 0);
+                                       methodListSection->atoms.push_back(newMetaClassRO);
+                               }
+                       }
+                       // if any category adds properties, generate new merged property list, and replace
+                       if ( OptimizeCategories<A>::hasProperties(state, categories) ) { 
+                               const ld::Atom* basePropertyListAtom = Class<A>::getInstancePropertyList(state, classAtom); 
+                               const ld::Atom* newPropertyListAtom = new PropertyListAtom<A>(state, basePropertyListAtom, categories, deadAtoms);
+                               const ld::Atom* newClassRO = Class<A>::setInstancePropertyList(state, classAtom, newPropertyListAtom, deadAtoms);
+                               // add new property list to final sections
+                               methodListSection->atoms.push_back(newPropertyListAtom);
+                               if ( newClassRO != NULL ) {
+                                       assert(strcmp(newClassRO->section().sectionName(), "__objc_const") == 0);
+                                       methodListSection->atoms.push_back(newClassRO);
+                               }
+                       }
+                
+               }
+
+               // remove dead atoms
+               for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
+                       ld::Internal::FinalSection* sect = *sit;
+                       sect->atoms.erase(std::remove_if(sect->atoms.begin(), sect->atoms.end(), OptimizedAway(deadAtoms)), sect->atoms.end());
+               }
+       }
+}
+
+
+template <typename A> 
+MethodListAtom<A>::MethodListAtom(ld::Internal& state, const ld::Atom* baseMethodList, bool meta, 
+                                                                       const std::vector<const ld::Atom*>* categories, std::set<const ld::Atom*>& deadAtoms)
+  : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                       ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified, 
+                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)), _file(NULL), _methodCount(0) 
+{
+       unsigned int fixupCount = 0;
+       // if base class has method list, then associate new method list with file defining class
+       if ( baseMethodList != NULL ) {
+               _file = baseMethodList->file();
+               // calculate total size of merge method lists
+               _methodCount = MethodList<A>::count(state, baseMethodList);
+               deadAtoms.insert(baseMethodList);
+               fixupCount = baseMethodList->fixupsEnd() - baseMethodList->fixupsBegin();
+       }
+       for (std::vector<const ld::Atom*>::const_iterator ait=categories->begin(); ait != categories->end(); ++ait) {
+               const ld::Atom* categoryMethodListAtom;
+               if ( meta )
+                       categoryMethodListAtom = Category<A>::getClassMethods(state, *ait);
+               else
+                       categoryMethodListAtom = Category<A>::getInstanceMethods(state, *ait);
+               if ( categoryMethodListAtom != NULL ) {
+                       _methodCount += MethodList<A>::count(state, categoryMethodListAtom);
+                       fixupCount += (categoryMethodListAtom->fixupsEnd() - categoryMethodListAtom->fixupsBegin());
+                       deadAtoms.insert(categoryMethodListAtom);
+                       // if base class did not have method list, associate new method list with file the defined category
+                       if ( _file == NULL )
+                               _file = categoryMethodListAtom->file();
+               }
+       }
+       //if ( baseMethodList != NULL )
+       //      fprintf(stderr, "total merged method count=%u for baseMethodList=%s\n", _methodCount, baseMethodList->name());
+       //else
+       //      fprintf(stderr, "total merged method count=%u\n", _methodCount);
+       //fprintf(stderr, "total merged fixup count=%u\n", fixupCount);
+       
+       // copy fixups and adjust offsets (in reverse order to simulator objc runtime)
+       _fixups.reserve(fixupCount);
+       uint32_t slide = 0;
+       for (std::vector<const ld::Atom*>::const_reverse_iterator rit=categories->rbegin(); rit != categories->rend(); ++rit) {
+               const ld::Atom* categoryMethodListAtom;
+               if ( meta )
+                       categoryMethodListAtom = Category<A>::getClassMethods(state, *rit);
+               else
+                       categoryMethodListAtom = Category<A>::getInstanceMethods(state, *rit);
+               if ( categoryMethodListAtom != NULL ) {
+                       for (ld::Fixup::iterator fit=categoryMethodListAtom->fixupsBegin(); fit != categoryMethodListAtom->fixupsEnd(); ++fit) {
+                               ld::Fixup fixup = *fit;
+                               fixup.offsetInAtom += slide;
+                               _fixups.push_back(fixup);
+                               //if ( fixup.binding == ld::Fixup::bindingDirectlyBound )
+                               //      fprintf(stderr, "offset=0x%08X, name=%s\n", fixup.offsetInAtom, fixup.u.target->name());
+                       }
+                       slide += 3*sizeof(pint_t) * MethodList<A>::count(state, categoryMethodListAtom);
+               }
+       }
+       // add method list from base class last
+       if ( baseMethodList != NULL ) {
+               for (ld::Fixup::iterator fit=baseMethodList->fixupsBegin(); fit != baseMethodList->fixupsEnd(); ++fit) {
+                       ld::Fixup fixup = *fit;
+                       fixup.offsetInAtom += slide;
+                       _fixups.push_back(fixup);
+               }
+       }
+}
+
+
+template <typename A> 
+ProtocolListAtom<A>::ProtocolListAtom(ld::Internal& state, const ld::Atom* baseProtocolList, 
+                                                                       const std::vector<const ld::Atom*>* categories, std::set<const ld::Atom*>& deadAtoms)
+  : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                       ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified, 
+                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)), _file(NULL), _protocolCount(0) 
+{
+       unsigned int fixupCount = 0;
+       if ( baseProtocolList != NULL ) {
+               // if base class has protocol list, then associate new protocol list with file defining class
+               _file = baseProtocolList->file();
+               // calculate total size of merged protocol list
+               _protocolCount = ProtocolList<A>::count(state, baseProtocolList);
+               deadAtoms.insert(baseProtocolList);
+               fixupCount = baseProtocolList->fixupsEnd() - baseProtocolList->fixupsBegin();
+       }
+       for (std::vector<const ld::Atom*>::const_iterator ait=categories->begin(); ait != categories->end(); ++ait) {
+               const ld::Atom* categoryProtocolListAtom = Category<A>::getProtocols(state, *ait);
+               if ( categoryProtocolListAtom != NULL ) {
+                       _protocolCount += ProtocolList<A>::count(state, categoryProtocolListAtom);
+                       fixupCount += (categoryProtocolListAtom->fixupsEnd() - categoryProtocolListAtom->fixupsBegin());
+                       deadAtoms.insert(categoryProtocolListAtom);
+                       // if base class did not have protocol list, associate new protocol list with file the defined category
+                       if ( _file == NULL )
+                               _file = categoryProtocolListAtom->file();
+               }
+       }
+       //fprintf(stderr, "total merged protocol count=%u\n", _protocolCount);
+       //fprintf(stderr, "total merged fixup count=%u\n", fixupCount);
+       
+       // copy fixups and adjust offsets 
+       _fixups.reserve(fixupCount);
+       uint32_t slide = 0;
+       for (std::vector<const ld::Atom*>::const_iterator it=categories->begin(); it != categories->end(); ++it) {
+               const ld::Atom* categoryProtocolListAtom = Category<A>::getProtocols(state, *it);
+               if ( categoryProtocolListAtom != NULL ) {
+                       for (ld::Fixup::iterator fit=categoryProtocolListAtom->fixupsBegin(); fit != categoryProtocolListAtom->fixupsEnd(); ++fit) {
+                               ld::Fixup fixup = *fit;
+                               fixup.offsetInAtom += slide;
+                               _fixups.push_back(fixup);
+                               //if ( fixup.binding == ld::Fixup::bindingDirectlyBound )
+                               //      fprintf(stderr, "offset=0x%08X, name=%s\n", fixup.offsetInAtom, fixup.u.target->name());
+                       }
+                       slide += sizeof(pint_t) * ProtocolList<A>::count(state, categoryProtocolListAtom);
+               }
+       }
+       // add method list from base class last
+       if ( baseProtocolList != NULL ) {
+               for (ld::Fixup::iterator fit=baseProtocolList->fixupsBegin(); fit != baseProtocolList->fixupsEnd(); ++fit) {
+                       ld::Fixup fixup = *fit;
+                       fixup.offsetInAtom += slide;
+                       _fixups.push_back(fixup);
+               }
+       }
+}
+
+
+template <typename A> 
+PropertyListAtom<A>::PropertyListAtom(ld::Internal& state, const ld::Atom* basePropertyList, 
+                                                                       const std::vector<const ld::Atom*>* categories, std::set<const ld::Atom*>& deadAtoms)
+  : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                       ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified, 
+                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)), _file(NULL), _propertyCount(0) 
+{
+       unsigned int fixupCount = 0;
+       if ( basePropertyList != NULL ) {
+               // if base class has property list, then associate new property list with file defining class
+               _file = basePropertyList->file();
+               // calculate total size of merged property list
+               _propertyCount = PropertyList<A>::count(state, basePropertyList);
+               deadAtoms.insert(basePropertyList);
+               fixupCount = basePropertyList->fixupsEnd() - basePropertyList->fixupsBegin();
+       }
+       for (std::vector<const ld::Atom*>::const_iterator ait=categories->begin(); ait != categories->end(); ++ait) {
+               const ld::Atom* categoryPropertyListAtom = Category<A>::getProperties(state, *ait);
+               if ( categoryPropertyListAtom != NULL ) {
+                       _propertyCount += PropertyList<A>::count(state, categoryPropertyListAtom);
+                       fixupCount += (categoryPropertyListAtom->fixupsEnd() - categoryPropertyListAtom->fixupsBegin());
+                       deadAtoms.insert(categoryPropertyListAtom);
+                       // if base class did not have property list, associate new property list with file the defined category
+                       if ( _file == NULL )
+                               _file = categoryPropertyListAtom->file();
+               }
+       }
+       //fprintf(stderr, "total merged property count=%u\n", _propertyCount);
+       //fprintf(stderr, "total merged fixup count=%u\n", fixupCount);
+       
+       // copy fixups and adjust offsets 
+       _fixups.reserve(fixupCount);
+       uint32_t slide = 0;
+       for (std::vector<const ld::Atom*>::const_iterator it=categories->begin(); it != categories->end(); ++it) {
+               const ld::Atom* categoryPropertyListAtom = Category<A>::getProperties(state, *it);
+               if ( categoryPropertyListAtom != NULL ) {
+                       for (ld::Fixup::iterator fit=categoryPropertyListAtom->fixupsBegin(); fit != categoryPropertyListAtom->fixupsEnd(); ++fit) {
+                               ld::Fixup fixup = *fit;
+                               fixup.offsetInAtom += slide;
+                               _fixups.push_back(fixup);
+                               //fprintf(stderr, "offset=0x%08X, binding=%d\n", fixup.offsetInAtom, fixup.binding);
+                               //if ( fixup.binding == ld::Fixup::bindingDirectlyBound )
+                               //      fprintf(stderr, "offset=0x%08X, name=%s\n", fixup.offsetInAtom, fixup.u.target->name());
+                               //else if ( fixup.binding == ld::Fixup::bindingsIndirectlyBound )
+                               //      fprintf(stderr, "offset=0x%08X, indirect index=%u, name=%s\n", fixup.offsetInAtom, fixup.u.bindingIndex, 
+                               //                      (char*)(state.indirectBindingTable[fixup.u.bindingIndex]->rawContentPointer()));
+                       }
+                       slide += 2*sizeof(pint_t) * PropertyList<A>::count(state, categoryPropertyListAtom);
+               }
+       }
+       // add method list from base class last
+       if ( basePropertyList != NULL ) {
+               for (ld::Fixup::iterator fit=basePropertyList->fixupsBegin(); fit != basePropertyList->fixupsEnd(); ++fit) {
+                       ld::Fixup fixup = *fit;
+                       fixup.offsetInAtom += slide;
+                       _fixups.push_back(fixup);
+               }
+       }
+}
+
+
+
+
+void doPass(const Options& opts, ld::Internal& state)
+{      
+       // only make image info section if objc was used
+       if ( state.objcObjectConstraint != ld::File::objcConstraintNone ) {
+
+               // verify dylibs are GC compatible with object files
+               if ( state.objcObjectConstraint != state.objcDylibConstraint ) {
+                       if (   (state.objcDylibConstraint == ld::File::objcConstraintRetainRelease)
+                               && (state.objcObjectConstraint == ld::File::objcConstraintGC) ) {
+                                       throw "Linked dylibs built for retain/release but object files built for GC-only";
+                       }
+                       else if (   (state.objcDylibConstraint == ld::File::objcConstraintGC)
+                                    && (state.objcObjectConstraint == ld::File::objcConstraintRetainRelease) ) {
+                                       throw "Linked dylibs built for GC-only but object files built for retain/release";
+                       }
+               }
+       
+               const bool compaction = opts.objcGcCompaction();
+               
+               // add image info atom
+               switch ( opts.architecture() ) {
+                       case CPU_TYPE_X86_64:
+                               state.addAtom(*new ObjCImageInfoAtom<x86_64>(state.objcObjectConstraint, compaction, 
+                                                               state.hasObjcReplacementClasses, true));
+                               break;
+                       case CPU_TYPE_I386:
+                               state.addAtom(*new ObjCImageInfoAtom<x86>(state.objcObjectConstraint, compaction, 
+                                                       state.hasObjcReplacementClasses, opts.objCABIVersion2POverride() ? true : false));
+                               break;
+                       case CPU_TYPE_POWERPC:
+                               state.addAtom(*new ObjCImageInfoAtom<ppc>(state.objcObjectConstraint, compaction, 
+                                                       state.hasObjcReplacementClasses, false));
+                               break;
+                       case CPU_TYPE_ARM:
+                               state.addAtom(*new ObjCImageInfoAtom<arm>(state.objcObjectConstraint, compaction, 
+                                                       state.hasObjcReplacementClasses, true));
+                               break;
+                       case CPU_TYPE_POWERPC64:
+                               state.addAtom(*new ObjCImageInfoAtom<ppc64>(state.objcObjectConstraint, compaction, 
+                                                       state.hasObjcReplacementClasses, true));
+                               break;
+                       default:
+                               assert(0 && "unknown objc arch");
+               }       
+       }
+       
+       if ( opts.objcCategoryMerging() ) {
+               // optimize classes defined in this linkage unit by merging in categories also in this linkage unit
+               switch ( opts.architecture() ) {
+                       case CPU_TYPE_X86_64:
+                               OptimizeCategories<x86_64>::doit(opts, state);
+                               break;
+                       case CPU_TYPE_I386:
+                               // disable optimization until fully tested
+                               //if ( opts.objCABIVersion2POverride() )
+                               //      OptimizeCategories<x86>::doit(opts, state);
+                               break;
+                       case CPU_TYPE_ARM:
+                               // disable optimization until fully tested
+                               //OptimizeCategories<arm>::doit(opts, state);
+                               break;
+                       case CPU_TYPE_POWERPC64:
+                       case CPU_TYPE_POWERPC:
+                               break;
+                       default:
+                               assert(0 && "unknown objc arch");
+               }       
+       }
+}
+
+
+} // namespace objc
+} // namespace passes 
+} // namespace ld 
diff --git a/src/ld/passes/objc.h b/src/ld/passes/objc.h
new file mode 100644 (file)
index 0000000..d92def6
--- /dev/null
@@ -0,0 +1,45 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#ifndef __OBJC_H__
+#define __OBJC_H__
+
+#include "Options.h"
+#include "ld.hpp"
+
+
+namespace ld {
+namespace passes {
+namespace objc {
+
+// called by linker to optimize ObjC data structures
+extern void doPass(const Options& opts, ld::Internal& internal);
+
+
+} // namespace objc
+} // namespace passes 
+} // namespace ld 
+
+#endif // __OBJC_H__
diff --git a/src/ld/passes/order_file.cpp b/src/ld/passes/order_file.cpp
new file mode 100644 (file)
index 0000000..9e336ae
--- /dev/null
@@ -0,0 +1,531 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <stdint.h>
+#include <math.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <mach/machine.h>
+
+#include <vector>
+#include <map>
+
+#include "ld.hpp"
+#include "order_file.h"
+
+namespace ld {
+namespace passes {
+namespace order_file {
+
+//
+// The purpose of this pass is to take the graph of all Atoms and produce an ordered
+// sequence of atoms.  The constraints are that: 1) all Atoms of the same Segment must
+// be contiguous, 2)  all Atoms of the same Section must be contigous, 3) Atoms specified
+// in an order_file are sequenced as in the order_file and before Atoms not specified,
+// 4) Atoms in the same section from the same .o file should be contiguous and sequenced
+// in the same order they were in the .o file, 5) Atoms in the same Section but which came
+// from different .o files should be sequenced in the same order that the .o files
+// were passed to the linker (i.e. command line order).
+//
+// The way this is implemented is that the linker passes a "base ordinal" to each File
+// as it is constructed. Add each atom has an objectAddress() method. Then
+// sorting is just sorting by section, then by file ordinal, then by object address.
+//
+// If an order_file is specified, it gets more complicated.  First, an override-ordinal map
+// is created.  It causes the sort routine to ignore the value returned by ordinal() and objectAddress() 
+// and use the override value instead.  Next some Atoms must be layed out consecutively
+// (e.g. hand written assembly that does not end with return, but rather falls into
+// the next label).  This is modeled in via a kindNoneFollowOn fixup.  The use of
+// kindNoneFollowOn fixups produces "clusters" of atoms that must stay together.
+// If an order_file tries to move one atom, it may need to move a whole cluster.  The
+// algorithm to do this models clusters using two maps.  The "starts" maps maps any
+// atom in a cluster to the first Atom in the cluster.  The "nexts" maps an Atom in a
+// cluster to the next Atom in the cluster.  With this in place, while processing an
+// order_file, if any entry is in a cluster (in "starts" map), then the entire cluster is
+// given ordinal overrides.
+//
+
+class Layout
+{
+public:
+                               Layout(const Options& opts, ld::Internal& state);
+       void            doPass();
+private:
+
+       class Comparer {
+       public:
+                                       Comparer(const Layout& l) : _layout(l) {}
+               bool            operator()(const ld::Atom* left, const ld::Atom* right);
+       private:
+               const Layout&   _layout;
+       };
+                               
+       class CStringEquals {
+       public:
+               bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+       };
+       typedef __gnu_cxx::hash_map<const char*, const ld::Atom*, __gnu_cxx::hash<const char*>, CStringEquals> NameToAtom;
+       
+       typedef std::map<const ld::Atom*, const ld::Atom*> AtomToAtom;
+       
+       typedef std::map<const ld::Atom*, uint32_t> AtomToOrdinal;
+       
+       const ld::Atom*         findAtom(const Options::OrderedSymbol& orderedSymbol);
+       void                            buildNameTable();
+       void                            buildFollowOnTables();
+       void                            buildOrdinalOverrideMap();
+       const ld::Atom*         follower(const ld::Atom* atom);
+       static bool                     matchesObjectFile(const ld::Atom* atom, const char* objectFileLeafName);
+                       bool            orderableSection(const ld::Internal::FinalSection*);
+       
+       const Options&                                          _options;
+       ld::Internal&                                           _state;
+       AtomToAtom                                                      _followOnStarts;
+       AtomToAtom                                                      _followOnNexts;
+       NameToAtom                                                      _nameTable;
+       std::vector<const ld::Atom*>            _nameCollisionAtoms;
+       AtomToOrdinal                                           _ordinalOverrideMap;
+       Comparer                                                        _comparer;
+       bool                                                            _haveOrderFile;
+
+       static bool                                                     _s_log;
+};
+
+bool Layout::_s_log = false;
+
+Layout::Layout(const Options& opts, ld::Internal& state)
+       : _options(opts), _state(state), _comparer(*this), _haveOrderFile(opts.orderedSymbolsCount() != 0)
+{
+}
+
+
+bool Layout::Comparer::operator()(const ld::Atom* left, const ld::Atom* right)
+{
+       if ( left == right )
+               return false;
+       
+       // magic section$start symbol always sorts to the start of its section
+       if ( left->contentType() == ld::Atom::typeSectionStart )
+               return true;
+       if ( right->contentType() == ld::Atom::typeSectionStart )
+               return false;
+
+       // if a -order_file is specified, then sorting is altered to sort those symbols first
+       if ( _layout._haveOrderFile ) {
+               AtomToOrdinal::const_iterator leftPos  = _layout._ordinalOverrideMap.find(left);
+               AtomToOrdinal::const_iterator rightPos = _layout._ordinalOverrideMap.find(right);
+               AtomToOrdinal::const_iterator end = _layout._ordinalOverrideMap.end();
+               if ( leftPos != end ) {
+                       if ( rightPos != end ) {
+                               // both left and right are overridden, so compare overridden ordinals
+                               return leftPos->second < rightPos->second;
+                       }
+                       else {
+                               // left is overridden and right is not, so left < right
+                               return true;
+                       }
+               }
+               else {
+                       if ( rightPos != end ) {
+                               // right is overridden and left is not, so right < left
+                               return false;
+                       }
+                       else {
+                               // neither are overridden, 
+                               // fall into default sorting below
+                       }
+               }
+       }
+
+       // magic section$end symbol always sorts to the end of its section
+       if ( left->contentType() == ld::Atom::typeSectionEnd )
+               return false;
+       if ( right->contentType() == ld::Atom::typeSectionEnd )
+               return true;
+
+       // the __common section can have real or tentative definitions
+       // we want the real ones to sort before tentative ones
+       bool leftIsTent  =  (left->definition() == ld::Atom::definitionTentative);
+       bool rightIsTent =  (right->definition() == ld::Atom::definitionTentative);
+       if ( leftIsTent != rightIsTent )
+               return rightIsTent; 
+
+#if 0  
+       // initializers are auto sorted to start of section
+       if ( !fInitializerSet.empty() ) {
+               bool leftFirst  = (fInitializerSet.count(left) != 0);
+               bool rightFirst = (fInitializerSet.count(right) != 0);
+               if ( leftFirst != rightFirst ) 
+                       return leftFirst;
+       }
+
+       // terminators are auto sorted to end of section
+       if ( !fTerminatorSet.empty() ) {
+               bool leftLast  = (fTerminatorSet.count(left) != 0);
+               bool rightLast = (fTerminatorSet.count(right) != 0);
+               if ( leftLast != rightLast ) 
+                       return rightLast;
+       }
+#endif
+       
+       // sort by .o order
+       uint32_t leftFileOrdinal = left->file()->ordinal();
+       uint32_t rightFileOrdinal = right->file()->ordinal();
+       if ( leftFileOrdinal != rightFileOrdinal )
+               return leftFileOrdinal< rightFileOrdinal;
+
+       // tentative defintions have no address in .o file, they are traditionally laid out by name
+       if ( leftIsTent && rightIsTent ) 
+               return (strcmp(left->name(), right->name()) < 0);
+
+       // lastly sort by atom address
+       int64_t addrDiff = left->objectAddress() - right->objectAddress();
+       if ( addrDiff == 0 ) {
+               // have same address so one might be an alias, and aliases need to sort before target
+               bool leftIsAlias = left->isAlias();
+               bool rightIsAlias = right->isAlias();
+               if ( leftIsAlias != rightIsAlias )
+                       return leftIsAlias;
+
+               // both at same address, sort by name 
+               return (strcmp(left->name(), right->name()) < 0);
+       }
+       return (addrDiff < 0);
+}
+
+bool Layout::matchesObjectFile(const ld::Atom* atom, const char* objectFileLeafName)
+{
+       if ( objectFileLeafName == NULL )
+               return true;
+       const char* atomFullPath = atom->file()->path();
+       const char* lastSlash = strrchr(atomFullPath, '/');
+       if ( lastSlash != NULL ) {
+               if ( strcmp(&lastSlash[1], objectFileLeafName) == 0 )
+                       return true;
+       }
+       else {
+               if ( strcmp(atomFullPath, objectFileLeafName) == 0 )
+                       return true;
+       }
+       return false;
+}
+
+
+bool Layout::orderableSection(const ld::Internal::FinalSection* sect)
+{
+       // atoms in only some sections are ordered 
+       switch ( sect->type() ) {
+               case ld::Section::typeUnclassified:
+               case ld::Section::typeCode:
+               case ld::Section::typeZeroFill:
+                       return true;
+               case ld::Section::typeImportProxies:
+                       return false;
+               default:
+                       // if section has command line aliases, then we must apply ordering so aliases layout before targets
+                       if ( _options.haveCmdLineAliases() ) {
+                               for (std::vector<const ld::Atom*>::const_iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+                                       const ld::Atom* atom = *ait;
+                                       if ( atom->isAlias() )
+                                               return true;
+                               }
+                       }
+                       break;
+       }
+       return false;
+}
+
+void Layout::buildNameTable()
+{
+       for (std::vector<ld::Internal::FinalSection*>::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) {
+               ld::Internal::FinalSection* sect = *sit;
+               // atoms in some special sections are never ordered 
+               if ( ! orderableSection(sect) )
+                       continue;
+               for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+                       const ld::Atom* atom = *ait;
+                       if ( atom->symbolTableInclusion() == ld::Atom::symbolTableIn ) {
+                               const char* name = atom->name();
+                               if ( name != NULL) {
+                                       // static function or data
+                                       NameToAtom::iterator pos = _nameTable.find(name);
+                                       if ( pos == _nameTable.end() )
+                                               _nameTable[name] = atom;
+                                       else {
+                                               _nameTable[name] = NULL;        // collision, denote with NULL
+                                               _nameCollisionAtoms.push_back(atom);
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+
+const ld::Atom* Layout::findAtom(const Options::OrderedSymbol& orderedSymbol)
+{
+       // look for name in _nameTable
+       NameToAtom::iterator pos = _nameTable.find(orderedSymbol.symbolName);
+       if ( pos != _nameTable.end() ) {
+               if ( (pos->second != NULL) && matchesObjectFile(pos->second, orderedSymbol.objectFileName) ) {
+                       //fprintf(stderr, "found %s in hash table\n", orderedSymbol.symbolName);
+                       return pos->second;
+               }
+               if ( pos->second == NULL ) {
+                       // name is in hash table, but atom is NULL, so that means there are duplicates, so we use super slow way
+                       for (std::vector<const ld::Atom*>::iterator it=_nameCollisionAtoms.begin(); it != _nameCollisionAtoms.end(); it++) {
+                               const ld::Atom* atom = *it;
+                               if ( strcmp(atom->name(), orderedSymbol.symbolName) == 0 ) {
+                                       if ( matchesObjectFile(atom, orderedSymbol.objectFileName) ) {
+                                               if ( _options.printOrderFileStatistics() )
+                                                       warning("%s specified in order_file but it exists in multiple .o files. "
+                                                                       "Prefix symbol with .o filename in order_file to disambiguate", orderedSymbol.symbolName);
+                                               return atom;
+                                       }
+                               }
+                       }
+               }
+       }
+               
+       return NULL;
+}
+
+const ld::Atom* Layout::follower(const ld::Atom* atom)
+{
+       for (const ld::Atom* a = _followOnStarts[atom]; a != NULL; a = _followOnNexts[a]) {
+               assert(a != NULL);
+               if ( _followOnNexts[a] == atom ) {
+                       return a;
+               }
+       }
+       // no follower, first in chain
+       return NULL;
+}
+
+void Layout::buildFollowOnTables()
+{
+       // first make a pass to find all follow-on references and build start/next maps
+       // which are a way to represent clusters of atoms that must layout together
+       for (std::vector<ld::Internal::FinalSection*>::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) {
+               ld::Internal::FinalSection* sect = *sit;
+               if ( !orderableSection(sect) ) 
+                       continue;
+               for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+                       const ld::Atom* atom = *ait;
+                       for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+                               if ( fit->kind == ld::Fixup::kindNoneFollowOn ) {
+                                       assert(fit->binding == ld::Fixup::bindingDirectlyBound);
+                                       const ld::Atom* followOnAtom = fit->u.target;
+                                       if ( _s_log ) fprintf(stderr, "ref %p %s -> %p %s\n", atom, atom->name(), followOnAtom, followOnAtom->name());
+                                       assert(_followOnNexts.count(atom) == 0);
+                                       _followOnNexts[atom] = followOnAtom;
+                                       if ( _followOnStarts.count(atom) == 0 ) {
+                                               // first time atom has been seen, make it start of chain
+                                               _followOnStarts[atom] = atom;
+                                               if ( _s_log ) fprintf(stderr, "  start %s -> %s\n", atom->name(), atom->name());
+                                       }
+                                       if ( _followOnStarts.count(followOnAtom) == 0 ) {
+                                               // first time followOnAtom has been seen, make atom start of chain
+                                               _followOnStarts[followOnAtom] = _followOnStarts[atom];
+                                               if ( _s_log ) fprintf(stderr, "  start %s -> %s\n", followOnAtom->name(), _followOnStarts[atom]->name());
+                                       }
+                                       else {
+                                               if ( _followOnStarts[followOnAtom] == followOnAtom ) {
+                                                       // followOnAtom atom already start of another chain, hook together 
+                                                       // and change all to use atom as start
+                                                       const ld::Atom* a = followOnAtom;
+                                                       while ( true ) {
+                                                               assert(_followOnStarts[a] == followOnAtom);
+                                                               _followOnStarts[a] = _followOnStarts[atom];
+                                                               if ( _s_log ) fprintf(stderr, "  adjust start for %s -> %s\n", a->name(), _followOnStarts[atom]->name());
+                                                               AtomToAtom::iterator pos = _followOnNexts.find(a);
+                                                               if ( pos != _followOnNexts.end() )
+                                                                       a = pos->second;
+                                                               else
+                                                                       break;
+                                                       }
+                                               }
+                                               else {
+                                                       // attempt to insert atom into existing followOn chain
+                                                       const ld::Atom* curPrevToFollowOnAtom = this->follower(followOnAtom);
+                                                       assert(curPrevToFollowOnAtom != NULL);
+                                                       assert((atom->size() == 0) || (curPrevToFollowOnAtom->size() == 0));
+                                                       if ( atom->size() == 0 ) {
+                                                               // insert alias into existing chain right before followOnAtom
+                                                               _followOnNexts[curPrevToFollowOnAtom] = atom;
+                                                               _followOnNexts[atom] = followOnAtom;
+                                                               _followOnStarts[atom] = _followOnStarts[followOnAtom];
+                                                       }
+                                                       else {
+                                                               // insert real atom into existing chain right before alias of followOnAtom
+                                                               const ld::Atom* curPrevPrevToFollowOn = this->follower(curPrevToFollowOnAtom);
+                                                               if ( curPrevPrevToFollowOn == NULL ) {
+                                                                       // nothing previous, so make this a start of a new chain
+                                                                       _followOnNexts[atom] = curPrevToFollowOnAtom;
+                                                                       for (const ld::Atom* a = atom; a != NULL; a = _followOnNexts[a]) {
+                                                                               if ( _s_log ) fprintf(stderr, "  adjust start for %s -> %s\n", a->name(), atom->name());
+                                                                               _followOnStarts[a] = atom;
+                                                                       }
+                                                               }
+                                                               else {
+                                                                       // is previous, insert into existing chain before previous
+                                                                       _followOnNexts[curPrevPrevToFollowOn] = atom;
+                                                                       _followOnNexts[atom] = curPrevToFollowOnAtom;
+                                                                       _followOnStarts[atom] = _followOnStarts[curPrevToFollowOnAtom];
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       if ( _s_log ) {
+               for(AtomToAtom::iterator it = _followOnStarts.begin(); it != _followOnStarts.end(); ++it)
+                       fprintf(stderr, "start %s -> %s\n", it->first->name(), it->second->name());
+
+               for(AtomToAtom::iterator it = _followOnNexts.begin(); it != _followOnNexts.end(); ++it)
+                       fprintf(stderr, "next %s -> %s\n", it->first->name(), (it->second != NULL) ? it->second->name() : "null");
+       }
+}
+
+void Layout::buildOrdinalOverrideMap()
+{
+       // if no -order_file, then skip building override map
+       if ( ! _haveOrderFile )
+               return;
+
+       // build fast name->atom table
+       this->buildNameTable();
+
+       // handle .o files that cannot have their atoms rearranged
+       // with the start/next maps of follow-on atoms we can process the order file and produce override ordinals
+       uint32_t index = 0;
+       uint32_t matchCount = 0;
+       for(Options::OrderedSymbolsIterator it = _options.orderedSymbolsBegin(); it != _options.orderedSymbolsEnd(); ++it) {
+               const ld::Atom* atom = this->findAtom(*it);
+               if ( atom != NULL ) {
+                       AtomToAtom::iterator start = _followOnStarts.find(atom);
+                       if ( start != _followOnStarts.end() ) {
+                               // this symbol for the order file corresponds to an atom that is in a cluster that must lay out together
+                               for(const ld::Atom* nextAtom = start->second; nextAtom != NULL; nextAtom = _followOnNexts[nextAtom]) {
+                                       AtomToOrdinal::iterator pos = _ordinalOverrideMap.find(nextAtom);
+                                       if ( pos == _ordinalOverrideMap.end() ) {
+                                               _ordinalOverrideMap[nextAtom] = index++;
+                                               if (_s_log ) fprintf(stderr, "override ordinal %u assigned to %s in cluster from %s\n", index, nextAtom->name(), nextAtom->file()->path());
+                                       }
+                                       else {
+                                               if (_s_log ) fprintf(stderr, "could not order %s as %u because it was already laid out earlier by %s as %u\n",
+                                                                               atom->name(), index, _followOnStarts[atom]->name(), _ordinalOverrideMap[atom] );
+                                       }
+                               }
+                       }
+                       else {
+                               _ordinalOverrideMap[atom] = index;
+                               if (_s_log ) fprintf(stderr, "override ordinal %u assigned to %s from %s\n", index, atom->name(), atom->file()->path());
+                       }
+                       ++matchCount;
+               }
+               else {
+                       if ( _options.printOrderFileStatistics() ) {
+                               if ( it->objectFileName == NULL )
+                                       warning("can't find match for order_file entry: %s", it->symbolName);
+                               else
+                                       warning("can't find match for order_file entry: %s/%s", it->objectFileName, it->symbolName);
+                       }
+               }
+                ++index;
+       }
+       if ( _options.printOrderFileStatistics() && (_options.orderedSymbolsCount() != matchCount) ) {
+               warning("only %u out of %lu order_file symbols were applicable", matchCount, _options.orderedSymbolsCount() );
+       }
+
+
+}
+
+void Layout::doPass()
+{
+       // handle .o files that cannot have their atoms rearranged
+       this->buildFollowOnTables();
+
+       //
+       this->buildOrdinalOverrideMap();
+
+
+       // sort atoms in each section
+       for (std::vector<ld::Internal::FinalSection*>::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) {
+               ld::Internal::FinalSection* sect = *sit;
+               if ( orderableSection(sect) ) {
+                       std::sort(sect->atoms.begin(), sect->atoms.end(), _comparer);
+               }
+               else {
+                       // bubble sort any typeSectionStart atom to the beginning
+                       bool moving = false;
+                       for (int i=sect->atoms.size()-1; i >= 0; --i) {
+                               if ( moving ) {
+                                       const ld::Atom* temp = sect->atoms[i];
+                                       sect->atoms[i] = sect->atoms[i+1];
+                                       sect->atoms[i+1] = temp;
+                               }
+                               if ( sect->atoms[i]->contentType() == ld::Atom::typeSectionStart ) 
+                                       moving = true;
+                       }
+                       // bubble sort any typeSectionEnd atom to the end
+                       moving = false;
+                       for (unsigned int i=sect->atoms.size(); i < sect->atoms.size(); ++i) {
+                               if ( moving ) {
+                                       const ld::Atom* temp = sect->atoms[i];
+                                       sect->atoms[i] = sect->atoms[i-1];
+                                       sect->atoms[i-1] = temp;
+                               }
+                               if ( sect->atoms[i]->contentType() == ld::Atom::typeSectionEnd ) 
+                                       moving = true;
+                       }
+               }
+       }
+       
+       //fprintf(stderr, "Sorted atoms:\n");
+       //for (std::vector<ld::Internal::FinalSection*>::iterator sit=_state.sections.begin(); sit != _state.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;
+       //              fprintf(stderr, "\t%s\t%s\n", sect->sectionName(), atom->name());
+       //      }
+       //}
+
+}
+
+
+void doPass(const Options& opts, ld::Internal& state)
+{
+       Layout layout(opts, state);
+       layout.doPass();
+}
+
+
+} // namespace order_file
+} // namespace passes 
+} // namespace ld 
diff --git a/src/ld/passes/order_file.h b/src/ld/passes/order_file.h
new file mode 100644 (file)
index 0000000..7a2aa87
--- /dev/null
@@ -0,0 +1,45 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#ifndef __ORDER_FILE_H__
+#define __ORDER_FILE_H__
+
+#include "Options.h"
+#include "ld.hpp"
+
+
+namespace ld {
+namespace passes {
+namespace order_file {
+
+// called by linker to re-arrange atoms to improve locality and performance
+extern void doPass(const Options& opts, ld::Internal& internal);
+
+
+} // namespace order_file
+} // namespace passes 
+} // namespace ld 
+
+#endif // __ORDER_FILE_H__
diff --git a/src/ld/passes/stubs/make_stubs.h b/src/ld/passes/stubs/make_stubs.h
new file mode 100644 (file)
index 0000000..7330bee
--- /dev/null
@@ -0,0 +1,39 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include "Options.h"
+#include "ld.hpp"
+
+namespace ld {
+namespace passes {
+namespace stubs {
+
+// called by linker to process atoms in Internal and add stubs as needed
+extern void doPass(const Options& opts, ld::Internal& internal);
+
+} // namespace stubs 
+} // namespace passes 
+} // namespace ld 
+
diff --git a/src/ld/passes/stubs/stub_arm.hpp b/src/ld/passes/stubs/stub_arm.hpp
new file mode 100644 (file)
index 0000000..e8dedda
--- /dev/null
@@ -0,0 +1,416 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009-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@
+ */
+
+// already in ld::passes::stubs namespace
+namespace arm {
+
+
+class FastBindingPointerAtom : public ld::Atom {
+public:
+                                                                                       FastBindingPointerAtom(ld::passes::stubs::Pass& pass)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)), 
+                               _fixup(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, pass.internal()->compressedFastBinderProxy)
+                                       { pass.addAtom(*this); }
+
+       virtual const ld::File*                                 file() const                                    { return NULL; }
+       virtual bool                                                    translationUnitSource(const char** dir, const char** nm) const 
+                                                                                                                                                       { return false; }
+       virtual const char*                                             name() const                                    { return "fast binder pointer"; }
+       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*)&_fixup; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup)[1]; }
+
+private:
+       ld::Fixup                                                               _fixup;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section FastBindingPointerAtom::_s_section("__DATA", "__nl_symbol_ptr", ld::Section::typeNonLazyPointer);
+
+
+class ImageCachePointerAtom : public ld::Atom {
+public:
+                                                                                       ImageCachePointerAtom(ld::passes::stubs::Pass& pass)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)) { pass.addAtom(*this); }
+
+       virtual const ld::File*                                 file() const                                    { return NULL; }
+       virtual bool                                                    translationUnitSource(const char** dir, const char** nm) const 
+                                                                                                                                                       { return false; }
+       virtual const char*                                             name() const                                    { return "non-lazy pointer"; }
+       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)                                 { }
+
+private:
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section ImageCachePointerAtom::_s_section("__DATA", "__nl_symbol_ptr", ld::Section::typeNonLazyPointer);
+
+
+
+class StubHelperHelperAtom : public ld::Atom {
+public:
+                                                                                       StubHelperHelperAtom(ld::passes::stubs::Pass& pass)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper, 
+                                                       ld::Atom::symbolTableIn, false, false, false, ld::Atom::Alignment(2)), 
+                               _fixup1(28, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, compressedImageCache(pass)),
+                               _fixup2(28, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, this),
+                               _fixup3(28, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, 16),
+                               _fixup4(28, ld::Fixup::k4of4, ld::Fixup::kindStoreLittleEndian32),
+                               _fixup5(32, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, compressedFastBinder(pass)),
+                               _fixup6(32, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, this),
+                               _fixup7(32, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, 28),
+                               _fixup8(32, ld::Fixup::k4of4, ld::Fixup::kindStoreLittleEndian32) 
+                                       { pass.addAtom(*this); }
+
+       virtual ld::File*                                               file() const                                    { return NULL; }
+       virtual bool                                                    translationUnitSource(const char** dir, const char** nm) const 
+                                                                                                                                                       { return false; }
+       virtual const char*                                             name() const                                    { return " stub helpers"; }
+       virtual uint64_t                                                size() const                                    { return 36; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+               // push lazy-info-offset
+               OSWriteLittleInt32(&buffer[ 0], 0, 0xe52dc004); // str ip, [sp, #-4]!
+               // push address of dyld_mageLoaderCache
+               OSWriteLittleInt32(&buffer[ 4], 0, 0xe59fc010); // ldr  ip, L1
+               OSWriteLittleInt32(&buffer[ 8], 0, 0xe08fc00c); // add  ip, pc, ip
+               OSWriteLittleInt32(&buffer[12], 0, 0xe52dc004); // str ip, [sp, #-4]!
+               // jump through _fast_lazy_bind
+               OSWriteLittleInt32(&buffer[16], 0, 0xe59fc008); // ldr  ip, L2
+               OSWriteLittleInt32(&buffer[20], 0, 0xe08fc00c); // add  ip, pc, ip
+               OSWriteLittleInt32(&buffer[24], 0, 0xe59cf000); // ldr  pc, [ip]
+               OSWriteLittleInt32(&buffer[28], 0, 0x00000000); // L1: .long fFastStubGOTAtom - (helperhelper+16)
+               OSWriteLittleInt32(&buffer[32], 0, 0x00000000); // L2: .long _fast_lazy_bind - (helperhelper+28)
+       }
+       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:
+       static ld::Atom* compressedImageCache(ld::passes::stubs::Pass& pass) {
+               if ( pass.compressedImageCache == NULL ) 
+                       pass.compressedImageCache = new ImageCachePointerAtom(pass);
+               return pass.compressedImageCache;               
+       }
+       static ld::Atom* compressedFastBinder(ld::passes::stubs::Pass& pass) {
+               if ( pass.compressedFastBinderPointer == NULL ) 
+                       pass.compressedFastBinderPointer = new FastBindingPointerAtom(pass);
+               return pass.compressedFastBinderPointer;                
+       }
+
+       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 StubHelperHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
+
+
+class StubHelperAtom : public ld::Atom {
+public:
+                                                                                       StubHelperAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo, 
+                                                                                                                                                                       const ld::Atom* lazyPointer)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)), 
+                               _stubTo(stubTo),  
+                               _fixup1(4, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARMBranch24, helperHelper(pass)),
+                               _fixup2(8, ld::Fixup::k1of2, ld::Fixup::kindSetLazyOffset, lazyPointer),
+                               _fixup3(8, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32) { }
+       
+       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 12; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+               OSWriteLittleInt32(&buffer[0], 0, 0xe59fc000); // ldr  ip, [pc, #0]
+               OSWriteLittleInt32(&buffer[4], 0, 0xea000000); // b     _helperhelper
+               OSWriteLittleInt32(&buffer[8], 0, 0);              // .long lazy-info-offset
+       }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return (ld::Fixup*)&_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd() const                               { return &((ld::Fixup*)&_fixup3)[1]; }
+
+private:
+       static ld::Atom* helperHelper(ld::passes::stubs::Pass& pass) {
+               if ( pass.compressedHelperHelper == NULL ) 
+                       pass.compressedHelperHelper = new StubHelperHelperAtom(pass);
+               return pass.compressedHelperHelper;
+       }
+       const ld::Atom&                                                 _stubTo;
+       ld::Fixup                                                               _fixup1;
+       ld::Fixup                                                               _fixup2;
+       ld::Fixup                                                               _fixup3;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section StubHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
+
+
+class ResolverHelperAtom : public ld::Atom {
+public:
+                                                                                       ResolverHelperAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo, 
+                                                                                                                                                                       const ld::Atom* lazyPointer)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper, 
+                                                       ld::Atom::symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)), 
+                               _stubTo(stubTo),  
+                               _fixup1( 4, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARMBranch24, &stubTo),
+                               _fixup2(32, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, lazyPointer),
+                               _fixup3(32, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, this),
+                               _fixup4(32, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, 20),
+                               _fixup5(32, ld::Fixup::k4of4, ld::Fixup::kindStoreLittleEndian32) { }
+       
+       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 36; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+               OSWriteLittleInt32(&buffer[ 0], 0, 0xe92d400f); // push {r0, r1, r2, r3, lr}
+               OSWriteLittleInt32(&buffer[ 4], 0, 0xebfffffd); // bl   _foo
+               OSWriteLittleInt32(&buffer[ 8], 0, 0xe59fc010); // ldr  ip, [pc, #16]
+               OSWriteLittleInt32(&buffer[12], 0, 0xe08fc00c); // add  ip, pc, ip
+               OSWriteLittleInt32(&buffer[16], 0, 0xe58c0000); // str  r0, [ip]
+               OSWriteLittleInt32(&buffer[20], 0, 0xe1a0c000); // mov  ip, r0
+               OSWriteLittleInt32(&buffer[24], 0, 0xe8bd400f); // pop  {r0, r1, r2, r3, lr}
+               OSWriteLittleInt32(&buffer[28], 0, 0xe12fff1c); // bx   ip
+               OSWriteLittleInt32(&buffer[32], 0, 0x00000000); // .long foo$lazyptr - helper + 20
+       }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return (ld::Fixup*)&_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd() const                               { return &((ld::Fixup*)&_fixup5)[1]; }
+
+private:
+       const ld::Atom&                                                 _stubTo;
+       ld::Fixup                                                               _fixup1;
+       ld::Fixup                                                               _fixup2;
+       ld::Fixup                                                               _fixup3;
+       ld::Fixup                                                               _fixup4;
+       ld::Fixup                                                               _fixup5;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section ResolverHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
+
+
+class LazyPointerAtom : public ld::Atom {
+public:
+                                                                                       LazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+                                                                                                                       bool stubToGlobalWeakDef, bool stubToResolver, 
+                                                                                                                       bool weakImport, bool close)
+                               : ld::Atom(close ? _s_sectionClose : _s_section, ld::Atom::definitionRegular, 
+                                                       ld::Atom::combineNever, ld::Atom::scopeLinkageUnit, ld::Atom::typeLazyPointer, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)), 
+                               _stubTo(stubTo),
+                               _helper(pass, stubTo, this),
+                               _resolverHelper(pass, stubTo, this),
+                               _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, 
+                                                               stubToResolver ? &_resolverHelper : (stubToGlobalWeakDef ?  &stubTo : &_helper)),
+                               _fixup2(0, ld::Fixup::k1of1, ld::Fixup::kindLazyTarget, &stubTo) { 
+                                               _fixup2.weakImport = weakImport; pass.addAtom(*this); 
+                                               if ( stubToResolver )
+                                                       pass.addAtom(_resolverHelper);
+                                               else if ( !stubToGlobalWeakDef ) 
+                                                       pass.addAtom(_helper); 
+                                       }
+
+       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*)&_fixup2)[1]; }
+
+private:
+       const ld::Atom&                                                 _stubTo;
+       StubHelperAtom                                                  _helper;
+       ResolverHelperAtom                                              _resolverHelper;
+       ld::Fixup                                                               _fixup1;
+       ld::Fixup                                                               _fixup2;
+       
+       static ld::Section                                              _s_section;
+       static ld::Section                                              _s_sectionClose;
+};
+
+ld::Section LazyPointerAtom::_s_section("__DATA", "__la_symbol_ptr", ld::Section::typeLazyPointer);
+ld::Section LazyPointerAtom::_s_sectionClose("__DATA", "__lazy_symbol", ld::Section::typeLazyPointerClose);
+
+
+
+class StubPICAtom : public ld::Atom {
+public:
+                                                                                       StubPICAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+                                                                                                               bool stubToGlobalWeakDef, bool stubToResolver, bool weakImport)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeStub, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)), 
+                               _stubTo(stubTo), 
+                               _lazyPointer(pass, stubTo, stubToGlobalWeakDef, stubToResolver, weakImport, false),
+                               _fixup1(12, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, &_lazyPointer),
+                               _fixup2(12, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, this),
+                               _fixup3(12, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, 12),
+                               _fixup4(12, ld::Fixup::k4of4, ld::Fixup::kindStoreLittleEndian32) 
+                               { 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 16; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+                       OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc004); //      ldr ip, pc + 12
+                       OSWriteLittleInt32(&buffer[ 4], 0, 0xe08fc00c); //      add ip, pc, ip
+                       OSWriteLittleInt32(&buffer[ 8], 0, 0xe59cf000); //      ldr pc, [ip]
+                       OSWriteLittleInt32(&buffer[12], 0, 0x00000000); //      .long L_foo$lazy_ptr - (L1$scv + 8)
+       }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return (ld::Fixup*)&_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup4)[1]; }
+
+private:
+       const ld::Atom&                                                 _stubTo;
+       LazyPointerAtom                                                 _lazyPointer;
+       ld::Fixup                                                               _fixup1;
+       ld::Fixup                                                               _fixup2;
+       ld::Fixup                                                               _fixup3;
+       ld::Fixup                                                               _fixup4;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section StubPICAtom::_s_section("__TEXT", "__picsymbolstub4", ld::Section::typeStub);
+
+
+
+class StubNoPICAtom : public ld::Atom {
+public:
+                                                                                       StubNoPICAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+                                                                                                               bool stubToGlobalWeakDef, bool stubToResolver, bool weakImport)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeStub, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)), 
+                               _stubTo(stubTo), 
+                               _lazyPointer(pass, stubTo, stubToGlobalWeakDef, stubToResolver, weakImport, false),
+                               _fixup(8, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, &_lazyPointer) 
+                                       { 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 12; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+                       OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc000); //      ldr ip, [pc, #0]
+                       OSWriteLittleInt32(&buffer[ 4], 0, 0xe59cf000); //      ldr pc, [ip]
+                       OSWriteLittleInt32(&buffer[ 8], 0, 0x00000000); //      .long   L_foo$lazy_ptr
+       }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return (ld::Fixup*)&_fixup; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup)[1]; }
+
+private:
+       const ld::Atom&                                                 _stubTo;
+       LazyPointerAtom                                                 _lazyPointer;
+       ld::Fixup                                                               _fixup;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section StubNoPICAtom::_s_section("__TEXT", "__symbol_stub4", ld::Section::typeStub);
+
+
+
+
+class StubCloseAtom : public ld::Atom {
+public:
+                                                                                       StubCloseAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+                                                                                                               bool stubToGlobalWeakDef, bool stubToResolver, bool weakImport)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeStub, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)), 
+                               _stubTo(stubTo), 
+                               _lazyPointer(pass, stubTo, stubToGlobalWeakDef, stubToResolver, weakImport, true),
+                               _fixup(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARMLoad12, &_lazyPointer) 
+                               { 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 {
+                       OSWriteLittleInt32(&buffer[ 0], 0, 0xE59FF000); //      ldr     pc, [pc, #foo$lazy_ptr]
+       }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return (ld::Fixup*)&_fixup; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup)[1]; }
+
+private:
+       const ld::Atom&                                                 _stubTo;
+       LazyPointerAtom                                                 _lazyPointer;
+       ld::Fixup                                                               _fixup;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section StubCloseAtom::_s_section("__TEXT", "__symbolstub1", ld::Section::typeStubClose);
+
+
+
+
+} // namespace arm 
+
diff --git a/src/ld/passes/stubs/stub_arm_classic.hpp b/src/ld/passes/stubs/stub_arm_classic.hpp
new file mode 100644 (file)
index 0000000..50870f4
--- /dev/null
@@ -0,0 +1,155 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+// already in ld::passes::stubs namespace
+namespace arm {
+namespace classic {
+
+
+class LazyPointerAtom : public ld::Atom {
+public:
+                                                                                       LazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+                                                                                                                       bool forLazyDylib, bool weakImport)
+                               : ld::Atom(forLazyDylib ? _s_sectionLazy : _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,
+                                               forLazyDylib ? pass.internal()->lazyBindingHelper : pass.internal()->classicBindingHelper),
+                               _fixup2(0, ld::Fixup::k1of1, ld::Fixup::kindLazyTarget, &stubTo)
+                                       { _fixup2.weakImport = weakImport; 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*)&_fixup2)[1]; }
+
+private:
+       const ld::Atom&                                                 _stubTo;
+       ld::Fixup                                                               _fixup1;
+       ld::Fixup                                                               _fixup2;
+       
+       static ld::Section                                              _s_section;
+       static ld::Section                                              _s_sectionLazy;
+};
+
+ld::Section LazyPointerAtom::_s_section("__DATA", "__la_symbol_ptr", ld::Section::typeLazyPointer);
+ld::Section LazyPointerAtom::_s_sectionLazy("__DATA", "__ld_symbol_ptr", ld::Section::typeLazyDylibPointer);
+
+
+class StubPICAtom : public ld::Atom {
+public:
+                                                                                       StubPICAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+                                                                                                                                       bool forLazyDylib, bool weakImport)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeStub, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)), 
+                               _stubTo(stubTo), 
+                               _lazyPointer(pass, stubTo, forLazyDylib, weakImport),
+                               _fixup1(12, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, &_lazyPointer),
+                               _fixup2(12, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, this),
+                               _fixup3(12, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, 12),
+                               _fixup4(12, ld::Fixup::k4of4, ld::Fixup::kindStoreLittleEndian32) 
+                               { 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 16; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+                       OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc004); //      ldr ip, pc + 12
+                       OSWriteLittleInt32(&buffer[ 4], 0, 0xe08fc00c); //      add ip, pc, ip
+                       OSWriteLittleInt32(&buffer[ 8], 0, 0xe59cf000); //      ldr pc, [ip]
+                       OSWriteLittleInt32(&buffer[12], 0, 0x00000000); //      .long L_foo$lazy_ptr - (L1$scv + 8)
+       }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return (ld::Fixup*)&_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup4)[1]; }
+
+private:
+       const ld::Atom&                                                 _stubTo;
+       LazyPointerAtom                                                 _lazyPointer;
+       ld::Fixup                                                               _fixup1;
+       ld::Fixup                                                               _fixup2;
+       ld::Fixup                                                               _fixup3;
+       ld::Fixup                                                               _fixup4;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section StubPICAtom::_s_section("__TEXT", "__picsymbolstub4", ld::Section::typeStub);
+
+
+
+class StubNoPICAtom : public ld::Atom {
+public:
+                                                                                       StubNoPICAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+                                                                                                                       bool forLazyDylib, bool weakImport)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeStub, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)), 
+                               _stubTo(stubTo), 
+                               _lazyPointer(pass, stubTo, forLazyDylib, weakImport),
+                               _fixup(8, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, &_lazyPointer) 
+                                       { 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 12; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+                       OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc000); //      ldr ip, [pc, #0]
+                       OSWriteLittleInt32(&buffer[ 4], 0, 0xe59cf000); //      ldr pc, [ip]
+                       OSWriteLittleInt32(&buffer[ 8], 0, 0x00000000); //      .long   L_foo$lazy_ptr
+       }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return (ld::Fixup*)&_fixup; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup)[1]; }
+
+private:
+       const ld::Atom&                                                 _stubTo;
+       LazyPointerAtom                                                 _lazyPointer;
+       ld::Fixup                                                               _fixup;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section StubNoPICAtom::_s_section("__TEXT", "__symbol_stub4", ld::Section::typeStub);
+
+
+
+
+} // namespace classic 
+} // namespace arm 
+
diff --git a/src/ld/passes/stubs/stub_ppc_classic.hpp b/src/ld/passes/stubs/stub_ppc_classic.hpp
new file mode 100644 (file)
index 0000000..6862b60
--- /dev/null
@@ -0,0 +1,190 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+// already in ld::passes::stubs namespace
+namespace ppc {
+namespace classic {
+
+
+
+class LazyPointerAtom : public ld::Atom {
+public:
+                                                                                       LazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo, 
+                                                                                                                                               bool forLazyDylib, bool for64, bool weakImport)
+                               : ld::Atom( forLazyDylib ? _s_sectionLazy : _s_section, 
+                                                       ld::Atom::definitionRegular, ld::Atom::combineNever, 
+                                                       ld::Atom::scopeTranslationUnit,
+                                                       forLazyDylib ? ld::Atom::typeLazyDylibPointer : ld::Atom::typeLazyPointer,
+                                                       symbolTableNotIn, false, false, false, for64 ? ld::Atom::Alignment(3) : ld::Atom::Alignment(2)), 
+                               _stubTo(stubTo),
+                               _fixup1(0, ld::Fixup::k1of1, 
+                                               for64 ? ld::Fixup::kindStoreTargetAddressBigEndian64 : ld::Fixup::kindStoreTargetAddressBigEndian32, 
+                                               forLazyDylib ? pass.internal()->lazyBindingHelper : pass.internal()->classicBindingHelper),
+                               _fixup2(0, ld::Fixup::k1of1, ld::Fixup::kindLazyTarget, &stubTo),
+                               _for64(for64)
+                                       {  _fixup2.weakImport = weakImport; 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 _for64 ? 8 : 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 &_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup2)[1]; }
+
+private:
+       const ld::Atom&                                                 _stubTo;
+       mutable ld::Fixup                                               _fixup1;
+       mutable ld::Fixup                                               _fixup2;
+       const bool                                                              _for64;
+       
+       static ld::Section                                              _s_section;
+       static ld::Section                                              _s_sectionLazy;
+};
+
+ld::Section LazyPointerAtom::_s_section("__DATA", "__la_symbol_ptr", ld::Section::typeLazyPointer);
+ld::Section LazyPointerAtom::_s_sectionLazy("__DATA", "__ld_symbol_ptr", ld::Section::typeLazyDylibPointer);
+
+
+
+class StubPICAtom : public ld::Atom {
+public:
+                                                                                       StubPICAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo, 
+                                                                                                                                               bool forLazyDylib, bool for64, bool weakImport)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeStub, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)), 
+                               _stubTo(stubTo), 
+                               _lazyPointer(pass, stubTo, forLazyDylib, for64, weakImport),
+                               _fixup1(12, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, &_lazyPointer), 
+                               _fixup2(12, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, this), 
+                               _fixup3(12, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, 8), 
+                               _fixup4(12, ld::Fixup::k4of4, ld::Fixup::kindStorePPCPicHigh16AddLow), 
+                               _fixup5(20, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, &_lazyPointer),
+                               _fixup6(20, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, this),
+                               _fixup7(20, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, 8), 
+                               _fixup8(20, ld::Fixup::k4of4, for64 ? ld::Fixup::kindStorePPCPicLow14 : ld::Fixup::kindStorePPCPicLow16),
+                               _for64(for64)
+                               { 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 32; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+               OSWriteBigInt32(&buffer[ 0], 0, 0x7c0802a6);    //      mflr r0
+               OSWriteBigInt32(&buffer[ 4], 0, 0x429f0005);    //  bcl 20,31,Lpicbase
+               OSWriteBigInt32(&buffer[ 8], 0, 0x7d6802a6);    // Lpicbase: mflr r11
+               OSWriteBigInt32(&buffer[12], 0, 0x3d6b0000);    //      addis r11,r11,ha16(L_fwrite$lazy_ptr-Lpicbase)
+               OSWriteBigInt32(&buffer[16], 0, 0x7c0803a6);    //      mtlr r0
+               if ( _for64 )
+                       OSWriteBigInt32(&buffer[20], 0, 0xe98b0001);//  ldu r12,lo16(L_fwrite$lazy_ptr-Lpicbase)(r11)
+               else
+                       OSWriteBigInt32(&buffer[20], 0, 0x858b0000);//  lwzu r12,lo16(L_fwrite$lazy_ptr-Lpicbase)(r11)
+               OSWriteBigInt32(&buffer[24], 0, 0x7d8903a6);    //  mtctr r12
+               OSWriteBigInt32(&buffer[28], 0, 0x4e800420);    //  bctr
+       }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return &_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup8)[1]; }
+
+private:
+       const ld::Atom&                                                 _stubTo;
+       LazyPointerAtom                                                 _lazyPointer;
+       mutable ld::Fixup                                               _fixup1;
+       mutable ld::Fixup                                               _fixup2;
+       mutable ld::Fixup                                               _fixup3;
+       mutable ld::Fixup                                               _fixup4;
+       mutable ld::Fixup                                               _fixup5;
+       mutable ld::Fixup                                               _fixup6;
+       mutable ld::Fixup                                               _fixup7;
+       mutable ld::Fixup                                               _fixup8;
+       const bool                                                              _for64;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section StubPICAtom::_s_section("__TEXT", "__picsymbolstub1", ld::Section::typeStub);
+
+
+
+class StubNoPICAtom : public ld::Atom {
+public:
+                                                                                       StubNoPICAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo, 
+                                                                                                                                               bool forLazyDylib, bool for64, bool weakImport)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeStub, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)), 
+                               _stubTo(stubTo), 
+                               _lazyPointer(pass, stubTo, forLazyDylib, for64, weakImport),
+                               _fixup1(0, ld::Fixup::k1of2, ld::Fixup::kindSetTargetAddress, &_lazyPointer), 
+                               _fixup2(0, ld::Fixup::k2of2, ld::Fixup::kindStorePPCAbsHigh16AddLow), 
+                               _fixup3(4, ld::Fixup::k1of2, ld::Fixup::kindSetTargetAddress, &_lazyPointer),
+                               _fixup4(4, ld::Fixup::k2of2, for64 ? ld::Fixup::kindStorePPCAbsLow14 : ld::Fixup::kindStorePPCAbsLow16),
+                               _for64(for64)
+                               { 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 16; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+               OSWriteBigInt32(&buffer[ 0], 0, 0x3d600000);    // lis r11,ha16(L_foo$lazy_ptr)
+               if ( _for64 )
+                       OSWriteBigInt32(&buffer[ 4], 0, 0xe98b0001);// ldu r12,lo16(L_foo$lazy_ptr)(r11)
+               else
+                       OSWriteBigInt32(&buffer[ 4], 0, 0x858b0000);// lwzu r12,lo16(L_foo$lazy_ptr)(r11)
+               OSWriteBigInt32(&buffer[ 8], 0, 0x7d8903a6);    // mtctr r12
+               OSWriteBigInt32(&buffer[12], 0, 0x4e800420);    // bctr
+       }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return &_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup4)[1]; }
+
+private:
+       const ld::Atom&                                                 _stubTo;
+       LazyPointerAtom                                                 _lazyPointer;
+       mutable ld::Fixup                                               _fixup1;
+       mutable ld::Fixup                                               _fixup2;
+       mutable ld::Fixup                                               _fixup3;
+       mutable ld::Fixup                                               _fixup4;
+       const bool                                                              _for64;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section StubNoPICAtom::_s_section("__TEXT", "__symbol_stub1", ld::Section::typeStub);
+
+
+} // namespace classic
+} // namespace ppc 
+
diff --git a/src/ld/passes/stubs/stub_x86.hpp b/src/ld/passes/stubs/stub_x86.hpp
new file mode 100644 (file)
index 0000000..0eda4ad
--- /dev/null
@@ -0,0 +1,347 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009-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@
+ */
+
+
+// already in ld::passes::stubs namespace
+namespace x86 {
+
+
+
+class FastBindingPointerAtom : public ld::Atom {
+public:
+                                                                                       FastBindingPointerAtom(ld::passes::stubs::Pass& pass)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)), 
+                               _fixup(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, 
+                                                               pass.internal()->compressedFastBinderProxy)
+                                       { pass.addAtom(*this); }
+
+       virtual const ld::File*                                 file() const                                    { return NULL; }
+       virtual bool                                                    translationUnitSource(const char** dir, const char** ) const 
+                                                                                                                                                       { return false; }
+       virtual const char*                                             name() const                                    { return "fast binder pointer"; }
+       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 &_fixup; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup)[1]; }
+
+private:
+       mutable ld::Fixup                                               _fixup;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section FastBindingPointerAtom::_s_section("__DATA", "__nl_symbol_ptr", ld::Section::typeNonLazyPointer);
+
+
+class ImageCachePointerAtom : public ld::Atom {
+public:
+                                                                                       ImageCachePointerAtom(ld::passes::stubs::Pass& pass)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)) { pass.addAtom(*this); }
+
+       virtual const ld::File*                                 file() const                                    { return NULL; }
+       virtual bool                                                    translationUnitSource(const char** dir, const char** ) const 
+                                                                                                                                                       { return false; }
+       virtual const char*                                             name() const                                    { return "image cache pointer"; }
+       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)                                 { }
+
+private:
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section ImageCachePointerAtom::_s_section("__DATA", "__nl_symbol_ptr", ld::Section::typeNonLazyPointer);
+
+
+
+
+
+//
+//  The stub-helper-helper is the common code factored out of each helper function.
+//  It is in the same section as the stub-helpers.  
+//  Similar to the PLT0 entry in ELF. 
+//
+class StubHelperHelperAtom : public ld::Atom {
+public:
+                                                                                       StubHelperHelperAtom(ld::passes::stubs::Pass& pass)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)), 
+                               _fixup1(1,  ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, compressedImageCache(pass)),
+                               _fixup2(7, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, compressedFastBinder(pass)) 
+                                       { pass.addAtom(*this); }
+
+       virtual ld::File*                                               file() const                                    { return NULL; }
+       virtual bool                                                    translationUnitSource(const char** dir, const char** ) const 
+                                                                                                                                                       { return false; }
+       virtual const char*                                             name() const                                    { return "helper helper"; }
+       virtual uint64_t                                                size() const                                    { return 12; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+                       buffer[0]  = 0x68;              // pushl $dyld_ImageLoaderCache
+                       buffer[1]  = 0x00;
+                       buffer[2]  = 0x00;
+                       buffer[3]  = 0x00;
+                       buffer[4]  = 0x00;
+                       buffer[5]  = 0xFF;              // jmp *_fast_lazy_bind
+                       buffer[6]  = 0x25;
+                       buffer[7]  = 0x00;
+                       buffer[8]  = 0x00;
+                       buffer[9]  = 0x00;
+                       buffer[10] = 0x00;
+                       buffer[11] = 0x90;              // nop
+       }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return &_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup2)[1]; }
+
+private:
+       static ld::Atom* compressedImageCache(ld::passes::stubs::Pass& pass) {
+               if ( pass.compressedImageCache == NULL ) 
+                       pass.compressedImageCache = new ImageCachePointerAtom(pass);
+               return pass.compressedImageCache;               
+       }
+       static ld::Atom* compressedFastBinder(ld::passes::stubs::Pass& pass) {
+               if ( pass.compressedFastBinderPointer == NULL ) 
+                       pass.compressedFastBinderPointer = new FastBindingPointerAtom(pass);
+               return pass.compressedFastBinderPointer;                
+       }
+       
+       mutable ld::Fixup                                               _fixup1;
+       ld::Fixup                                                               _fixup2;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section StubHelperHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
+
+
+
+class StubHelperAtom : public ld::Atom {
+public:
+                                                                                       StubHelperAtom(ld::passes::stubs::Pass& pass, const ld::Atom* lazyPointer,
+                                                                                                                                                                                       const ld::Atom& stubTo)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(1)), 
+                               _stubTo(stubTo),
+                               _fixup1(1, ld::Fixup::k1of2, ld::Fixup::kindSetLazyOffset, lazyPointer),
+                               _fixup2(1, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32),
+                               _fixup3(6, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86BranchPCRel32, helperHelper(pass)) { }
+                               
+       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 10; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+                       buffer[0]  = 0x68;              // pushl $lazy-info-offset
+                       buffer[1]  = 0x00;
+                       buffer[2]  = 0x00;
+                       buffer[3]  = 0x00;
+                       buffer[4]  = 0x00;
+                       buffer[5]  = 0xE9;              // jmp helperhelper
+                       buffer[6]  = 0x00;
+                       buffer[7]  = 0x00;
+                       buffer[8]  = 0x00;
+                       buffer[9]  = 0x00;
+       }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return &_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd() const                               { return &((ld::Fixup*)&_fixup3)[1]; }
+
+private:
+       static ld::Atom* helperHelper(ld::passes::stubs::Pass& pass) {
+               if ( pass.compressedHelperHelper == NULL ) 
+                       pass.compressedHelperHelper = new StubHelperHelperAtom(pass);
+               return pass.compressedHelperHelper;
+       }
+
+       const ld::Atom&                                                 _stubTo;
+       mutable ld::Fixup                                               _fixup1;
+                       ld::Fixup                                               _fixup2;
+                       ld::Fixup                                               _fixup3;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section                                            StubHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
+
+
+class ResolverHelperAtom : public ld::Atom {
+public:
+                                                                                       ResolverHelperAtom(ld::passes::stubs::Pass& pass, const ld::Atom* lazyPointer,
+                                                                                                                                                                                       const ld::Atom& stubTo)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(1)), 
+                               _stubTo(stubTo),
+                               _fixup1(4,  ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86BranchPCRel32, &stubTo),
+                               _fixup2(9,  ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, lazyPointer),
+                               _fixup3(18, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, lazyPointer) { }
+                               
+       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 22; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+                       buffer[ 0]  = 0x50;             // push %eax
+                       buffer[ 1]  = 0x51;             // push %ecx
+                       buffer[ 2]  = 0x52;             // push %edx
+                       buffer[ 3]  = 0xE8;             // call foo
+                       buffer[ 4]  = 0x00;
+                       buffer[ 5]  = 0x00;             
+                       buffer[ 6]  = 0x00;
+                       buffer[ 7]  = 0x00;
+                       buffer[ 8]  = 0xA3;             // movl %eax,foo$lazy_ptr
+                       buffer[ 9]  = 0x00;
+                       buffer[10]  = 0x00;     
+                       buffer[11]  = 0x00;
+                       buffer[12]  = 0x00;
+                       buffer[13]  = 0x5A;             // pop %edx
+                       buffer[14]  = 0x59;             // pop %ecx
+                       buffer[15]  = 0x58;             // pop %eax
+                       buffer[16]  = 0xFF;             // jmp *foo$lazy_ptr
+                       buffer[17]  = 0x25;
+                       buffer[18]  = 0x00;
+                       buffer[19]  = 0x00;
+                       buffer[20]  = 0x00;
+                       buffer[21]  = 0x00;
+       }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return &_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd() const                               { return &((ld::Fixup*)&_fixup3)[1]; }
+
+private:
+
+       const ld::Atom&                                                 _stubTo;
+       mutable ld::Fixup                                               _fixup1;
+                       ld::Fixup                                               _fixup2;
+                       ld::Fixup                                               _fixup3;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section                                            ResolverHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
+
+
+
+class LazyPointerAtom : public ld::Atom {
+public:
+                                                                                       LazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+                                                                                                               bool stubToGlobalWeakDef, bool stubToResolver, bool weakImport)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeTranslationUnit, ld::Atom::typeLazyPointer, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)), 
+                               _stubTo(stubTo),
+                               _helper(pass, this, stubTo),
+                               _resolverHelper(pass, this, stubTo),
+                               _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, 
+                                                                       stubToResolver ? &_resolverHelper : (stubToGlobalWeakDef ?  &stubTo : &_helper)),
+                               _fixup2(0, ld::Fixup::k1of1, ld::Fixup::kindLazyTarget, &stubTo) { 
+                                               _fixup2.weakImport = weakImport; pass.addAtom(*this); 
+                                               if ( stubToResolver )
+                                                       pass.addAtom(_resolverHelper);
+                                               else if ( !stubToGlobalWeakDef ) 
+                                                       pass.addAtom(_helper); 
+                               }
+
+       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 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 &_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup2)[1]; }
+
+private:
+       const ld::Atom&                                                 _stubTo;
+       StubHelperAtom                                                  _helper;
+       ResolverHelperAtom                                              _resolverHelper;
+       mutable ld::Fixup                                               _fixup1;
+       ld::Fixup                                                               _fixup2;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section LazyPointerAtom::_s_section("__DATA", "__la_symbol_ptr", ld::Section::typeLazyPointer);
+
+
+class StubAtom : public ld::Atom {
+public:
+                                                                                       StubAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+                                                                                                       bool stubToGlobalWeakDef, bool stubToResolver, bool weakImport)
+                               : 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), 
+                               _lazyPointer(pass, stubTo, stubToGlobalWeakDef, stubToResolver, weakImport),
+                               _fixup(2, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, &_lazyPointer) { 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$lazy_pointer
+                       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;
+       LazyPointerAtom                                                 _lazyPointer;
+       mutable ld::Fixup                                               _fixup;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section StubAtom::_s_section("__TEXT", "__symbol_stub", ld::Section::typeStub);
+
+
+
+} // namespace x86
+
diff --git a/src/ld/passes/stubs/stub_x86_64.hpp b/src/ld/passes/stubs/stub_x86_64.hpp
new file mode 100644 (file)
index 0000000..e74b37d
--- /dev/null
@@ -0,0 +1,366 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+// already in ld::passes::stubs namespace
+namespace x86_64 {
+
+
+
+class FastBindingPointerAtom : public ld::Atom {
+public:
+                                                                                       FastBindingPointerAtom(ld::passes::stubs::Pass& pass)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)), 
+                               _fixup(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64, 
+                                                                                               pass.internal()->compressedFastBinderProxy)
+                                       { pass.addAtom(*this); }
+
+       virtual const ld::File*                                 file() const                                    { return NULL; }
+       virtual bool                                                    translationUnitSource(const char** dir, const char** nm) const 
+                                                                                                                                                       { return false; }
+       virtual const char*                                             name() const                                    { return "fast binder pointer"; }
+       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 &_fixup; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup)[1]; }
+
+private:
+       mutable ld::Fixup                                               _fixup;
+
+       static ld::Section                                              _s_section;
+};
+
+ld::Section FastBindingPointerAtom::_s_section("__DATA", "__nl_symbol_ptr", ld::Section::typeNonLazyPointer);
+
+
+class ImageCachePointerAtom : public ld::Atom {
+public:
+                                                                                       ImageCachePointerAtom(ld::passes::stubs::Pass& pass)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)) { pass.addAtom(*this); }
+
+       virtual const ld::File*                                 file() const                                    { return NULL; }
+       virtual bool                                                    translationUnitSource(const char** dir, const char** nm) const 
+                                                                                                                                                       { return false; }
+       virtual const char*                                             name() const                                    { return "image cache pointer"; }
+       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)                                 { }
+
+private:
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section ImageCachePointerAtom::_s_section("__DATA", "__nl_symbol_ptr", ld::Section::typeNonLazyPointer);
+
+
+
+
+
+//
+//  The stub-helper-helper is the common code factored out of each helper function.
+//  It is in the same section as the stub-helpers.  
+//  Similar to the PLT0 entry in ELF. 
+//
+class StubHelperHelperAtom : public ld::Atom {
+public:
+                                                                                       StubHelperHelperAtom(ld::passes::stubs::Pass& pass)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)), 
+                               _fixup1(3,  ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86PCRel32, compressedImageCache(pass)),
+                               _fixup2(11, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86PCRel32, compressedFastBinder(pass)) 
+                                       { pass.addAtom(*this); }
+
+       virtual ld::File*                                               file() const                                    { return NULL; }
+       virtual bool                                                    translationUnitSource(const char** dir, const char** nm) const 
+                                                                                                                                                       { return false; }
+       virtual const char*                                             name() const                                    { return "helper helper"; }
+       virtual uint64_t                                                size() const                                    { return 16; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+               buffer[0]  = 0x4C;              // leaq dyld_mageLoaderCache(%rip),%r11
+               buffer[1]  = 0x8D;
+               buffer[2]  = 0x1D;
+               buffer[3]  = 0x00;
+               buffer[4]  = 0x00;
+               buffer[5]  = 0x00;
+               buffer[6]  = 0x00;
+               buffer[7]  = 0x41;              // pushq %r11
+               buffer[8]  = 0x53;
+               buffer[9]  = 0xFF;              // jmp *_fast_lazy_bind(%rip)
+               buffer[10] = 0x25;
+               buffer[11] = 0x00;
+               buffer[12] = 0x00;
+               buffer[13] = 0x00;
+               buffer[14] = 0x00;
+               buffer[15] = 0x90;              // nop
+       }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return &_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup2)[1]; }
+
+private:
+       static ld::Atom* compressedImageCache(ld::passes::stubs::Pass& pass) {
+               if ( pass.compressedImageCache == NULL ) 
+                       pass.compressedImageCache = new ImageCachePointerAtom(pass);
+               return pass.compressedImageCache;               
+       }
+       static ld::Atom* compressedFastBinder(ld::passes::stubs::Pass& pass) {
+               if ( pass.compressedFastBinderPointer == NULL ) 
+                       pass.compressedFastBinderPointer = new FastBindingPointerAtom(pass);
+               return pass.compressedFastBinderPointer;                
+       }
+       
+       mutable ld::Fixup                                               _fixup1;
+       ld::Fixup                                                               _fixup2;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section StubHelperHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
+
+
+
+class StubHelperAtom : public ld::Atom {
+public:
+                                                                                       StubHelperAtom(ld::passes::stubs::Pass& pass, const ld::Atom* lazyPointer,
+                                                                                                                                                                                       const ld::Atom& stubTo)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(1)), 
+                               _stubTo(stubTo),
+                               _fixup1(1, ld::Fixup::k1of2, ld::Fixup::kindSetLazyOffset, lazyPointer),
+                               _fixup2(1, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32),
+                               _fixup3(6, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86BranchPCRel32, helperHelper(pass)) { }
+                               
+       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 10; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+                       buffer[0]  = 0x68;              // pushq $lazy-info-offset
+                       buffer[1]  = 0x00;
+                       buffer[2]  = 0x00;
+                       buffer[3]  = 0x00;
+                       buffer[4]  = 0x00;
+                       buffer[5]  = 0xE9;              // jmp helperhelper
+                       buffer[6]  = 0x00;
+                       buffer[7]  = 0x00;
+                       buffer[8]  = 0x00;
+                       buffer[9]  = 0x00;
+       }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return &_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd() const                               { return &((ld::Fixup*)&_fixup3)[1]; }
+
+private:
+       static ld::Atom* helperHelper(ld::passes::stubs::Pass& pass) {
+               if ( pass.compressedHelperHelper == NULL ) 
+                       pass.compressedHelperHelper = new StubHelperHelperAtom(pass);
+               return pass.compressedHelperHelper;
+       }
+
+       const ld::Atom&                                                 _stubTo;
+       mutable ld::Fixup                                               _fixup1;
+                       ld::Fixup                                               _fixup2;
+                       ld::Fixup                                               _fixup3;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section                                            StubHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
+
+
+class ResolverHelperAtom : public ld::Atom {
+public:
+                                                                                       ResolverHelperAtom(ld::passes::stubs::Pass& pass, const ld::Atom* lazyPointer,
+                                                                                                                                                                                       const ld::Atom& stubTo)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(1)), 
+                               _stubTo(stubTo),
+                               _fixup1(10, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86BranchPCRel32, &stubTo),
+                               _fixup2(17, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86PCRel32, lazyPointer),
+                               _fixup3(32, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86PCRel32, lazyPointer) { }
+                               
+       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 36; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+                       buffer[ 0]  = 0x50;             // push %rax
+                       buffer[ 1]  = 0x57;             // push %rdi
+                       buffer[ 2]  = 0x56;             // push %rsi
+                       buffer[ 3]  = 0x52;             // push %rdx
+                       buffer[ 4]  = 0x51;             // push %rcx
+                       buffer[ 5]  = 0x41;             // push %r8
+                       buffer[ 6]  = 0x50;
+                       buffer[ 7]  = 0x41;             // push %r9
+                       buffer[ 8]  = 0x51;
+                       buffer[ 9]  = 0xE8;             // call foo
+                       buffer[10]  = 0x00;
+                       buffer[11]  = 0x00;
+                       buffer[12]  = 0x00;             
+                       buffer[13]  = 0x00;
+                       buffer[14]  = 0x48;             // movq %rax,foo$lazy_pointer(%rip)
+                       buffer[15]  = 0x89;
+                       buffer[16]  = 0x05;
+                       buffer[17]  = 0x00;
+                       buffer[18]  = 0x00;
+                       buffer[19]  = 0x00;
+                       buffer[20]  = 0x00;
+                       buffer[21]  = 0x41;             // pop %r9
+                       buffer[22]  = 0x59;     
+                       buffer[23]  = 0x41;             // pop %r8
+                       buffer[24]  = 0x58;
+                       buffer[25]  = 0x59;             // pop %rcx
+                       buffer[26]  = 0x5A;             // pop %rdx
+                       buffer[27]  = 0x5E;             // pop %rsi
+                       buffer[28]  = 0x5F;             // pop %rdi
+                       buffer[29]  = 0x58;             // pop %rax
+                       buffer[30]  = 0xFF;             // jmp *foo$lazy_ptr(%rip)
+                       buffer[31]  = 0x25;
+                       buffer[32]  = 0x00;
+                       buffer[33]  = 0x00;
+                       buffer[34]  = 0x00;
+                       buffer[35]  = 0x00;
+       }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return &_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd() const                               { return &((ld::Fixup*)&_fixup3)[1]; }
+
+private:
+
+       const ld::Atom&                                                 _stubTo;
+       mutable ld::Fixup                                               _fixup1;
+                       ld::Fixup                                               _fixup2;
+                       ld::Fixup                                               _fixup3;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section                                            ResolverHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
+
+
+
+class LazyPointerAtom : public ld::Atom {
+public:
+                                                                                       LazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+                                                                                                                       bool stubToGlobalWeakDef, bool stubToResolver, bool weakImport)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeTranslationUnit, ld::Atom::typeLazyPointer, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)), 
+                               _stubTo(stubTo),
+                               _helper(pass, this, stubTo),
+                               _resolverHelper(pass, this, stubTo),
+                               _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64, 
+                                                                                                       stubToResolver ? &_resolverHelper : 
+                                                                                                               (stubToGlobalWeakDef ?  &stubTo : &_helper)),
+                               _fixup2(0, ld::Fixup::k1of1, ld::Fixup::kindLazyTarget, &stubTo) { 
+                                               _fixup2.weakImport = weakImport; pass.addAtom(*this); 
+                                               if ( stubToResolver )
+                                                       pass.addAtom(_resolverHelper);
+                                               else if ( !stubToGlobalWeakDef ) 
+                                                       pass.addAtom(_helper); 
+                                       }
+
+       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 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 &_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup2)[1]; }
+
+private:
+       const ld::Atom&                                                 _stubTo;
+       StubHelperAtom                                                  _helper;
+       ResolverHelperAtom                                              _resolverHelper;
+       mutable ld::Fixup                                               _fixup1;
+       ld::Fixup                                                               _fixup2;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section LazyPointerAtom::_s_section("__DATA", "__la_symbol_ptr", ld::Section::typeLazyPointer);
+
+
+class StubAtom : public ld::Atom {
+public:
+                                                                                       StubAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+                                                                                                       bool stubToGlobalWeakDef, bool stubToResolver, bool weakImport)
+                               : 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), 
+                               _lazyPointer(pass, stubTo, stubToGlobalWeakDef, stubToResolver, weakImport),
+                               _fixup(2, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86PCRel32, &_lazyPointer) { 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$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;
+       LazyPointerAtom                                                 _lazyPointer;
+       mutable ld::Fixup                                               _fixup;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section StubAtom::_s_section("__TEXT", "__stubs", ld::Section::typeStub);
+
+
+
+} // namespace x86_64 
+
diff --git a/src/ld/passes/stubs/stub_x86_64_classic.hpp b/src/ld/passes/stubs/stub_x86_64_classic.hpp
new file mode 100644 (file)
index 0000000..14507a2
--- /dev/null
@@ -0,0 +1,165 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+// already in ld::passes::stubs namespace
+namespace x86_64 {
+namespace classic {
+
+
+
+
+class StubHelperAtom : public ld::Atom {
+public:
+                                       StubHelperAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo, 
+                                                                                                                               const ld::Atom& lazyPointer, bool forLazyDylib)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)), 
+                               _stubTo(stubTo), 
+                               _fixup1(3, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86PCRel32, &lazyPointer),
+                               _fixup2(8, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86BranchPCRel32, 
+                                               forLazyDylib ? pass.internal()->lazyBindingHelper : pass.internal()->classicBindingHelper) 
+                                       { 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 12; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+                       buffer[0]  = 0x4C;              // lea foo$lazy_ptr(%rip),%r11
+                       buffer[1]  = 0x8D;
+                       buffer[2]  = 0x1D;
+                       buffer[3]  = 0x00;
+                       buffer[4]  = 0x00;
+                       buffer[5]  = 0x00;
+                       buffer[6]  = 0x00;
+                       buffer[7]  = 0xE9;              // jmp dyld_stub_binding_helper
+                       buffer[8]  = 0x00;
+                       buffer[9]  = 0x00;
+                       buffer[10] = 0x00;
+                       buffer[11] = 0x00;
+       }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return &_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd() const                               { return &((ld::Fixup*)&_fixup2)[1]; }
+
+private:
+       const ld::Atom&                                                 _stubTo;
+       mutable ld::Fixup                                               _fixup1;
+       mutable ld::Fixup                                               _fixup2;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section StubHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
+
+
+
+class LazyPointerAtom : public ld::Atom {
+public:
+                                                                                       LazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo, 
+                                                                                                                                                                       bool forLazyDylib, bool weakImport)
+                               : ld::Atom( forLazyDylib ? _s_sectionLazy : _s_section, 
+                                                       ld::Atom::definitionRegular, ld::Atom::combineNever, 
+                                                       ld::Atom::scopeTranslationUnit,
+                                                       forLazyDylib ? ld::Atom::typeLazyDylibPointer : ld::Atom::typeLazyPointer,
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)), 
+                               _stubTo(stubTo),
+                               _helper(pass, stubTo, *this, forLazyDylib),
+                               _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64, &_helper),
+                               _fixup2(0, ld::Fixup::k1of1, ld::Fixup::kindLazyTarget, &stubTo)
+                                       { _fixup2.weakImport = weakImport; 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 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 &_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup2)[1]; }
+
+private:
+       const ld::Atom&                                                 _stubTo;
+       StubHelperAtom                                                  _helper;
+       mutable ld::Fixup                                               _fixup1;
+       mutable ld::Fixup                                               _fixup2;
+       
+       static ld::Section                                              _s_section;
+       static ld::Section                                              _s_sectionLazy;
+};
+
+ld::Section LazyPointerAtom::_s_section("__DATA", "__la_symbol_ptr", ld::Section::typeLazyPointer);
+ld::Section LazyPointerAtom::_s_sectionLazy("__DATA", "__ld_symbol_ptr", ld::Section::typeLazyDylibPointer);
+
+
+
+class StubAtom : public ld::Atom {
+public:
+                                                                                       StubAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo, 
+                                                                                                                                                                       bool forLazyDylib, bool weakImport)
+                               : 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), 
+                               _lazyPointer(pass, stubTo, forLazyDylib, weakImport),
+                               _fixup(2, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86PCRel32, &_lazyPointer) { 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$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;
+       LazyPointerAtom                                                 _lazyPointer;
+       mutable ld::Fixup                                               _fixup;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section StubAtom::_s_section("__TEXT", "__stubs", ld::Section::typeStub);
+
+
+} // namespace classic
+} // namespace x86_64 
+
diff --git a/src/ld/passes/stubs/stub_x86_classic.hpp b/src/ld/passes/stubs/stub_x86_classic.hpp
new file mode 100644 (file)
index 0000000..0562218
--- /dev/null
@@ -0,0 +1,163 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+// already in ld::passes::stubs namespace
+namespace x86 {
+namespace classic {
+
+
+
+
+class StubHelperAtom : public ld::Atom {
+public:
+                                       StubHelperAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo, 
+                                                                                                                               const ld::Atom& lazyPointer, bool forLazyDylib)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)), 
+                               _stubTo(stubTo), 
+                               _fixup1(1, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, &lazyPointer),
+                               _fixup2(6, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86BranchPCRel32, 
+                                               forLazyDylib ? pass.internal()->lazyBindingHelper : pass.internal()->classicBindingHelper) 
+                                       { 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 10; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+                       buffer[0]  = 0x68;              // pushl $foo$lazy_ptr
+                       buffer[1]  = 0x00;
+                       buffer[2]  = 0x00;
+                       buffer[3]  = 0x00;
+                       buffer[4]  = 0x00;
+                       buffer[5]  = 0xE9;              // jmp dyld_stub_binding_helper
+                       buffer[6]  = 0x00;
+                       buffer[7]  = 0x00;
+                       buffer[8]  = 0x00;
+                       buffer[9]  = 0x00;
+       }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return &_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd() const                               { return &((ld::Fixup*)&_fixup2)[1]; }
+
+private:
+       const ld::Atom&                                                 _stubTo;
+       mutable ld::Fixup                                               _fixup1;
+       mutable ld::Fixup                                               _fixup2;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section StubHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
+
+
+
+class LazyPointerAtom : public ld::Atom {
+public:
+                                                                                       LazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo, 
+                                                                                                                                                                       bool forLazyDylib, bool weakImport)
+                               : ld::Atom( forLazyDylib ? _s_sectionLazy : _s_section, 
+                                                       ld::Atom::definitionRegular, ld::Atom::combineNever, 
+                                                       ld::Atom::scopeTranslationUnit,
+                                                       forLazyDylib ? ld::Atom::typeLazyDylibPointer : ld::Atom::typeLazyPointer,
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)), 
+                               _stubTo(stubTo),
+                               _helper(pass, stubTo, *this, forLazyDylib),
+                               _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, &_helper),
+                               _fixup2(0, ld::Fixup::k1of1, ld::Fixup::kindLazyTarget, &stubTo)
+                                       { _fixup2.weakImport = weakImport; 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 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 &_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup2)[1]; }
+
+private:
+       const ld::Atom&                                                 _stubTo;
+       StubHelperAtom                                                  _helper;
+       mutable ld::Fixup                                               _fixup1;
+       mutable ld::Fixup                                               _fixup2;
+       
+       static ld::Section                                              _s_section;
+       static ld::Section                                              _s_sectionLazy;
+};
+
+ld::Section LazyPointerAtom::_s_section("__DATA", "__la_symbol_ptr", ld::Section::typeLazyPointer);
+ld::Section LazyPointerAtom::_s_sectionLazy("__DATA", "__ld_symbol_ptr", ld::Section::typeLazyDylibPointer);
+
+
+
+class StubAtom : public ld::Atom {
+public:
+                                                                                       StubAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo, 
+                                                                                                                                                                       bool forLazyDylib, bool weakImport)
+                               : 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), 
+                               _lazyPointer(pass, stubTo, forLazyDylib, weakImport),
+                               _fixup(2, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, &_lazyPointer) { 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$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;
+       LazyPointerAtom                                                 _lazyPointer;
+       mutable ld::Fixup                                               _fixup;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section StubAtom::_s_section("__TEXT", "__symbol_stub", ld::Section::typeStub);
+
+
+} // namespace classic
+} // namespace x86 
+
diff --git a/src/ld/passes/stubs/stubs.cpp b/src/ld/passes/stubs/stubs.cpp
new file mode 100644 (file)
index 0000000..0e23c27
--- /dev/null
@@ -0,0 +1,385 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+
+#include <stdint.h>
+#include <math.h>
+#include <unistd.h>
+#include <assert.h>
+#include <libkern/OSByteOrder.h>
+
+#include <vector>
+#include <set>
+#include <map>
+
+#include "Options.h"
+#include "ld.hpp"
+
+#include "make_stubs.h"
+
+
+namespace ld {
+namespace passes {
+namespace stubs {
+
+class Pass {
+public:
+                                                               Pass(const Options& opts);
+       void                                            process(ld::Internal& internal);
+       void                                            addAtom(const ld::Atom& atom)   { _internal->addAtom(atom); }
+       bool                                            usingCompressedLINKEDIT() const { return _compressedLINKEDIT; }
+       ld::Internal*                           internal() { return _internal; }
+
+       Atom*                                           compressedHelperHelper;
+       Atom*                                           compressedImageCache;
+       Atom*                                           compressedFastBinderPointer;
+
+private:
+
+       struct AtomByNameSorter
+       {
+                bool operator()(const ld::Atom* left, const ld::Atom* right)
+                {
+                         return (strcmp(left->name(), right->name()) < 0);
+                }
+       };
+
+       const ld::Atom*                         stubableFixup(const ld::Fixup* fixup, ld::Internal&);
+       ld::Atom*                                       makeStub(const ld::Atom& target, bool weakImport);
+       void                                            verifyNoResolverFunctions(ld::Internal& state);
+
+       const Options&                          _options;
+       const cpu_type_t                        _architecture;
+       const bool                                      _lazyDylibsInUuse;
+       const bool                                      _compressedLINKEDIT;
+       const bool                                      _prebind;
+       const bool                                      _mightBeInSharedRegion;
+       const bool                                      _pic;
+       const bool                                      _flatNamespace;
+       ld::Internal*                           _internal;
+       uint32_t                                        _stubCount;
+       bool                                            _largeText;
+};
+
+#include "stub_x86_64.hpp"
+#include "stub_x86_64_classic.hpp"
+#include "stub_x86.hpp"
+#include "stub_x86_classic.hpp"
+#include "stub_arm.hpp"
+#include "stub_arm_classic.hpp"
+#include "stub_ppc_classic.hpp"
+
+
+
+Pass::Pass(const Options& opts) 
+       :       compressedHelperHelper(NULL), 
+               compressedImageCache(NULL),
+               compressedFastBinderPointer(NULL),
+               _options(opts),
+               _architecture(opts.architecture()),
+               _lazyDylibsInUuse(opts.usingLazyDylibLinking()),
+               _compressedLINKEDIT(opts.makeCompressedDyldInfo()),
+               _prebind(opts.prebind()),
+               _mightBeInSharedRegion(opts.sharedRegionEligible()), 
+               _pic(opts.outputSlidable()),
+               _flatNamespace(opts.nameSpace() != Options::kTwoLevelNameSpace),
+               _internal(NULL), _stubCount(0), _largeText(false)
+{
+       
+} 
+
+
+const ld::Atom* Pass::stubableFixup(const ld::Fixup* fixup, ld::Internal& state)
+{
+       if ( fixup->binding == ld::Fixup::bindingsIndirectlyBound ) {
+               const ld::Atom* target = state.indirectBindingTable[fixup->u.bindingIndex];
+               switch ( fixup->kind ) {
+                       case ld::Fixup::kindStoreTargetAddressPPCBranch24:
+                       case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
+                       case ld::Fixup::kindStoreTargetAddressARMBranch24:
+                       case ld::Fixup::kindStoreTargetAddressThumbBranch22:
+                               // create stub if target is in a dylib
+                               if ( target->definition() == ld::Atom::definitionProxy ) 
+                                       return target;
+                               // use stub if target is a resolver function in same linkage unit
+                               if ( target->contentType() == ld::Atom::typeResolver ) 
+                                       return target;
+                               if ( target->scope() == ld::Atom::scopeGlobal ) {       
+                                       // create stub if target is global weak definition in symbol table
+                                       if ( (target->definition() == ld::Atom::definitionRegular) 
+                                               && (target->combine() == ld::Atom::combineByName) 
+                                               && ((target->symbolTableInclusion() == ld::Atom::symbolTableIn) 
+                                                || (target->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip)) )
+                                               return target;
+                                       // create stub if target is interposable
+                                       if ( _options.interposable(target->name()) ) 
+                                               return target;
+                                       if ( _flatNamespace ) {
+                                               // flat namespace does not indirect calls within main exectuables
+                                               if ( _options.outputKind() == Options::kDynamicExecutable ) 
+                                                       return NULL;
+                                               // create stub if target is global and building -flat dylib or bundle
+                                               return target;
+                                       }
+                               }
+                               break;
+                       default:
+                               if ( target->contentType() == ld::Atom::typeResolver ) {
+                                       // any pointer to a resolver needs to change to pointer to stub
+                                       return target;
+                               }
+                               break;
+               }
+       }
+       return NULL;
+}
+
+
+
+ld::Atom* Pass::makeStub(const ld::Atom& target, bool weakImport)
+{
+       //fprintf(stderr, "makeStub(target=%p %s in sect %s)\n", &target, target.name(), target.section().sectionName());
+       bool stubToGlobalWeakDef = ( (target.scope() == ld::Atom::scopeGlobal)
+                                                               && (target.definition() == ld::Atom::definitionRegular) 
+                                                               && (target.combine() == ld::Atom::combineByName) );
+
+       bool forLazyDylib = false;
+       const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(target.file());
+       if ( (dylib != NULL) && dylib->willBeLazyLoadedDylib() ) 
+               forLazyDylib = true;
+       bool stubToResolver = (target.contentType() == ld::Atom::typeResolver);
+       
+       switch ( _architecture ) {
+               case CPU_TYPE_POWERPC: 
+                       if ( _pic )
+                               return new ld::passes::stubs::ppc::classic::StubPICAtom(*this, target, forLazyDylib, false, weakImport);
+                       else
+                               return new ld::passes::stubs::ppc::classic::StubNoPICAtom(*this, target, forLazyDylib, false, weakImport);
+                       break;
+               case CPU_TYPE_POWERPC64: 
+                       return new ld::passes::stubs::ppc::classic::StubPICAtom(*this, target, forLazyDylib, true, weakImport);
+                       break;
+               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;
+               case CPU_TYPE_X86_64:
+                       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;
+               case CPU_TYPE_ARM: 
+                       if ( usingCompressedLINKEDIT() && !forLazyDylib ) {
+                               if ( (_stubCount < 900) && !_mightBeInSharedRegion && !_largeText )
+                                       return new ld::passes::stubs::arm::StubCloseAtom(*this, target, stubToGlobalWeakDef, stubToResolver, weakImport);
+                               else if ( _pic )
+                                       return new ld::passes::stubs::arm::StubPICAtom(*this, target, stubToGlobalWeakDef, stubToResolver, weakImport);
+                               else
+                                       return new ld::passes::stubs::arm::StubNoPICAtom(*this, target, stubToGlobalWeakDef, stubToResolver, weakImport);
+                       } 
+                       else {
+                               if ( _pic )
+                                       return new ld::passes::stubs::arm::classic::StubPICAtom(*this, target, forLazyDylib, weakImport);
+                               else
+                                       return new ld::passes::stubs::arm::classic::StubNoPICAtom(*this, target, forLazyDylib, weakImport);
+                       }
+                       break;
+       }
+       throw "unsupported arch for stub";
+}
+
+
+void Pass::verifyNoResolverFunctions(ld::Internal& state)
+{
+       for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.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->contentType() == ld::Atom::typeResolver ) 
+                               throwf("resolver function '%s' not supported in type of output", atom->name());
+               }
+       }
+}
+
+void Pass::process(ld::Internal& state)
+{
+       switch ( _options.outputKind() ) {
+               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:
+                       // these kinds don't use stubs and cannot have resolver functions
+                       verifyNoResolverFunctions(state);
+                       return;
+               case Options::kDynamicLibrary:
+                       // uses stubs and can have resolver functions
+                       break;
+               case Options::kDynamicExecutable:
+               case Options::kDynamicBundle:
+                       // these kinds do use stubs and cannot have resolver functions
+                       verifyNoResolverFunctions(state);
+                       break;
+       }
+       
+       // walk all atoms and fixups looking for stubable references
+       // don't create stubs inline because that could invalidate the sections iterator
+       std::vector<const ld::Atom*> atomsCallingStubs;
+       std::map<const ld::Atom*,ld::Atom*> stubFor;
+       std::map<const ld::Atom*,bool>          weakImportMap;
+       atomsCallingStubs.reserve(128);
+       uint64_t codeSize = 0;
+       for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.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;
+                       codeSize += atom->size();
+                       bool atomNeedsStub = false;
+                       for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+                               const ld::Atom* stubableTargetOfFixup = stubableFixup(fit, state);
+                               if ( stubableTargetOfFixup != NULL ) {
+                                       if ( !atomNeedsStub ) {
+                                               atomsCallingStubs.push_back(atom);
+                                               atomNeedsStub = true;
+                                       }
+                                       stubFor[stubableTargetOfFixup] = NULL;  
+                                       // record weak_import attribute
+                                       std::map<const ld::Atom*,bool>::iterator pos = weakImportMap.find(stubableTargetOfFixup);
+                                       if ( pos == weakImportMap.end() ) {
+                                               // target not in weakImportMap, so add
+                                               weakImportMap[stubableTargetOfFixup] = fit->weakImport;
+                                               // <rdar://problem/5529626> If only weak_import symbols are used, linker should use LD_LOAD_WEAK_DYLIB
+                                               const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(stubableTargetOfFixup->file());
+                                               if ( dylib != NULL ) {
+                                                       if ( fit->weakImport )
+                                                               (const_cast<ld::dylib::File*>(dylib))->setUsingWeakImportedSymbols();
+                                                       else
+                                                               (const_cast<ld::dylib::File*>(dylib))->setUsingNonWeakImportedSymbols();
+                                               }
+                                       }
+                                       else {
+                                               // target in weakImportMap, check for weakness mismatch
+                                               if ( pos->second != fit->weakImport ) {
+                                                       // found mismatch
+                                                       switch ( _options.weakReferenceMismatchTreatment() ) {
+                                                               case Options::kWeakReferenceMismatchError:
+                                                                       throwf("mismatching weak references for symbol: %s", stubableTargetOfFixup->name());
+                                                               case Options::kWeakReferenceMismatchWeak:
+                                                                       pos->second = true;
+                                                                       break;
+                                                               case Options::kWeakReferenceMismatchNonWeak:
+                                                                       pos->second = false;
+                                                                       break;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                       // all resolver functions must have a corresponding stub
+                       if ( atom->contentType() == ld::Atom::typeResolver ) {
+                               if ( _options.outputKind() != Options::kDynamicLibrary ) 
+                                       throwf("resolver functions (%s) can only be used in dylibs", atom->name());
+                               if ( !_options.makeCompressedDyldInfo() ) {
+                                       if ( _options.architecture() == CPU_TYPE_POWERPC )
+                                               throwf("resolver functions (%s) not supported for PowerPC", atom->name());
+                                       else if ( _options.architecture() == CPU_TYPE_ARM )
+                                               throwf("resolver functions (%s) can only be used when targeting iOS 4.2 or later", atom->name());
+                                       else
+                                               throwf("resolver functions (%s) can only be used when targeting Mac OS X 10.6 or later", atom->name());
+                               }
+                               stubFor[atom] = NULL;   
+                       }
+               }
+       }
+       
+       // short circuit if no stubs needed
+       _internal = &state;
+       _stubCount = stubFor.size();
+       if ( _stubCount == 0 )
+               return;
+       
+       // <rdar://problem/8553283> lazily check for helper
+       if ( !_options.makeCompressedDyldInfo() && (state.classicBindingHelper == NULL) ) 
+               throw "symbol dyld_stub_binding_helper not found, normally in crt1.o/dylib1.o/bundle1.o";
+
+       // disable close stubs when branch islands might be needed
+       if ( (_architecture == CPU_TYPE_ARM) && (codeSize > 4*1024*1024) )
+               _largeText = true;
+       
+       // make stub atoms 
+       for (std::map<const ld::Atom*,ld::Atom*>::iterator it = stubFor.begin(); it != stubFor.end(); ++it) {
+               it->second = makeStub(*it->first, weakImportMap[it->first]);
+       }
+       
+       // updated atoms to use stubs
+       for (std::vector<const ld::Atom*>::iterator it=atomsCallingStubs.begin(); it != atomsCallingStubs.end(); ++it) {
+               const ld::Atom* atom = *it;
+               for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+                       const ld::Atom* stubableTargetOfFixup = stubableFixup(fit, state);
+                       if ( stubableTargetOfFixup != NULL ) {
+                               ld::Atom* stub = stubFor[stubableTargetOfFixup];
+                               assert(stub != NULL && "stub not created");
+                               fit->binding = ld::Fixup::bindingDirectlyBound;
+                               fit->u.target = stub;
+                       }
+               }
+       }
+       
+       // 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;
+               switch ( sect->type() ) {
+                       case ld::Section::typeStubHelper:
+                       case ld::Section::typeStub:
+                       case ld::Section::typeStubClose:
+                       case ld::Section::typeLazyPointer:
+                       case ld::Section::typeLazyPointerClose:
+                               std::sort(sect->atoms.begin(), sect->atoms.end(), AtomByNameSorter());
+                               break;
+                       default:
+                               break;
+               }
+       }
+
+}
+
+
+void doPass(const Options& opts, ld::Internal& internal)
+{
+       Pass  pass(opts);
+       pass.process(internal);
+}
+
+
+
+} // namespace stubs 
+} // namespace passes 
+} // namespace ld 
+
diff --git a/src/ld/passes/tlvp.cpp b/src/ld/passes/tlvp.cpp
new file mode 100644 (file)
index 0000000..f40d018
--- /dev/null
@@ -0,0 +1,303 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <stdint.h>
+#include <math.h>
+#include <unistd.h>
+#include <dlfcn.h>
+
+#include <vector>
+#include <map>
+#include <ext/hash_map>
+
+#include "ld.hpp"
+#include "tlvp.h"
+
+namespace ld {
+namespace passes {
+namespace tlvp {
+
+class File; // forward reference
+
+class TLVEntryAtom : public ld::Atom {
+public:
+                                                                                       TLVEntryAtom(ld::Internal& internal, const ld::Atom* target, bool weakImport)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)), 
+                               _fixup(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64, target),
+                               _target(target)
+                                       { _fixup.weakImport = weakImport; internal.addAtom(*this); }
+
+       virtual const ld::File*                                 file() const                                    { return NULL; }
+       virtual bool                                                    translationUnitSource(const char** dir, const char**) const 
+                                                                                                                                                       { return false; }
+       virtual const char*                                             name() const                                    { return _target->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 &_fixup; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup)[1]; }
+
+private:
+       mutable ld::Fixup                                               _fixup;
+       const ld::Atom*                                                 _target;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section TLVEntryAtom::_s_section("__DATA", "__thread_ptrs", ld::Section::typeTLVPointers);
+
+
+static bool optimizable(const Options& opts, const ld::Atom* targetOfTLV)
+{
+       // cannot do LEA optimization if target is in another dylib
+       if ( targetOfTLV->definition() == ld::Atom::definitionProxy ) 
+               return false;
+       if ( targetOfTLV->scope() == ld::Atom::scopeGlobal ) {  
+               // cannot do LEA optimization if target is weak exported symbol
+               if ( (targetOfTLV->definition() == ld::Atom::definitionRegular) && (targetOfTLV->combine() == ld::Atom::combineByName) )
+                       return false;
+               // cannot do LEA optimization if target is interposable
+               if ( opts.interposable(targetOfTLV->name()) ) 
+                       return false;
+               // cannot do LEA optimization for flat-namespace
+               if ( opts.nameSpace() != Options::kTwoLevelNameSpace ) 
+                       return false;
+       }
+       return true;
+}
+
+struct AtomByNameSorter
+{
+        bool operator()(const ld::Atom* left, const ld::Atom* right)
+        {
+                 return (strcmp(left->name(), right->name()) < 0);
+        }
+};
+
+struct TlVReferenceCluster
+{
+       const ld::Atom* targetOfTLV;
+       ld::Fixup*              fixupWithTarget;
+       ld::Fixup*              fixupWithTLVStore;
+       bool                    optimizable;
+};
+
+void doPass(const Options& opts, ld::Internal& internal)
+{
+       const bool log = false;
+       
+       // only make tlv section in final linked images
+       if ( opts.outputKind() == Options::kObjectFile )
+               return;
+
+       // walk all atoms and fixups looking for TLV references and add them to list
+       std::vector<TlVReferenceCluster>        references;
+       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;
+                       TlVReferenceCluster ref;
+                       for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+                               if ( fit->firstInCluster() ) {
+                                       ref.targetOfTLV = NULL;
+                                       ref.fixupWithTarget = NULL;
+                                       ref.fixupWithTLVStore = NULL;
+                               }
+                               switch ( fit->binding ) {
+                                       case ld::Fixup::bindingsIndirectlyBound:
+                                               ref.targetOfTLV = internal.indirectBindingTable[fit->u.bindingIndex];
+                                               ref.fixupWithTarget = fit;
+                                               break;
+                                       case ld::Fixup::bindingDirectlyBound:
+                                               ref.targetOfTLV = fit->u.target;
+                                               ref.fixupWithTarget = fit;
+                                               break;
+                    default:
+                        break;    
+                               }
+                               switch ( fit->kind ) {
+                                       case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
+                                       case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad:
+                                       case ld::Fixup::kindStoreX86PCRel32TLVLoad:
+                                       case ld::Fixup::kindStoreX86Abs32TLVLoad:
+                                               ref.fixupWithTLVStore = fit;
+                                               break;
+                                       default:
+                                               break;
+                               }
+                               if ( fit->lastInCluster() && (ref.fixupWithTLVStore != NULL) ) {
+                                       ref.optimizable = optimizable(opts, ref.targetOfTLV);
+                                       if (log) fprintf(stderr, "found reference to TLV at %s+0x%X to %s\n", 
+                                                                       atom->name(), ref.fixupWithTLVStore->offsetInAtom, ref.targetOfTLV->name());
+                                       if ( ! opts.canUseThreadLocalVariables() ) {
+                                               throwf("targeted OS version does not support use of thread local variables in %s", atom->name());
+                                       }
+                                       references.push_back(ref);
+                               }
+                       }
+               }
+       }
+       
+       // compute which TLV references will be weak_imports
+       std::map<const ld::Atom*,bool>          weakImportMap;
+       for(std::vector<TlVReferenceCluster>::iterator it=references.begin(); it != references.end(); ++it) {
+               if ( !it->optimizable ) {
+                       // record weak_import attribute
+                       std::map<const ld::Atom*,bool>::iterator pos = weakImportMap.find(it->targetOfTLV);
+                       if ( pos == weakImportMap.end() ) {
+                               // target not in weakImportMap, so add
+                               weakImportMap[it->targetOfTLV] = it->fixupWithTarget->weakImport;
+                               // <rdar://problem/5529626> If only weak_import symbols are used, linker should use LD_LOAD_WEAK_DYLIB
+                               const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(it->targetOfTLV->file());
+                               if ( dylib != NULL ) {
+                                       if ( it->fixupWithTarget->weakImport )
+                                               (const_cast<ld::dylib::File*>(dylib))->setUsingWeakImportedSymbols();
+                                       else
+                                               (const_cast<ld::dylib::File*>(dylib))->setUsingNonWeakImportedSymbols();
+                               }
+                       }
+                       else {
+                               // target in weakImportMap, check for weakness mismatch
+                               if ( pos->second != it->fixupWithTarget->weakImport ) {
+                                       // found mismatch
+                                       switch ( opts.weakReferenceMismatchTreatment() ) {
+                                               case Options::kWeakReferenceMismatchError:
+                                                       throwf("mismatching weak references for symbol: %s", it->targetOfTLV->name());
+                                               case Options::kWeakReferenceMismatchWeak:
+                                                       pos->second = true;
+                                                       break;
+                                               case Options::kWeakReferenceMismatchNonWeak:
+                                                       pos->second = false;
+                                                       break;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       // create TLV pointers for TLV references that cannot be optimized
+       std::map<const ld::Atom*,ld::Atom*> variableToPointerMap;
+       for(std::map<const ld::Atom*,bool>::iterator it=weakImportMap.begin(); it != weakImportMap.end(); ++it) {
+               std::map<const ld::Atom*,ld::Atom*>::iterator pos = variableToPointerMap.find(it->first);
+               if ( pos == variableToPointerMap.end() ) {
+                       if (log) fprintf(stderr, "make TLV pointer for %s\n", it->first->name());
+                       if ( it->first->contentType() != ld::Atom::typeTLV )
+                               throwf("illegal thread local variable reference to regular symbol %s", it->first->name());
+                       TLVEntryAtom* tlvp = new TLVEntryAtom(internal, it->first, it->second);
+                       variableToPointerMap[it->first] = tlvp;
+               }
+       }
+
+       // sort new tvlp atoms so links are consistent
+       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::typeTLVPointers ) {
+                       std::sort(sect->atoms.begin(), sect->atoms.end(), AtomByNameSorter());
+               }
+       }
+
+       // update references to use TLV pointers or TLV object directly
+       for(std::vector<TlVReferenceCluster>::iterator it=references.begin(); it != references.end(); ++it) {
+               if ( it->optimizable ) {
+                       // change store to be LEA instead load (mov)
+                       if (log) fprintf(stderr, "optimizing load of TLV to %s into an LEA\n", it->targetOfTLV->name());
+                       it->fixupWithTLVStore->binding = ld::Fixup::bindingDirectlyBound;
+                       it->fixupWithTLVStore->u.target = it->targetOfTLV;
+                       switch ( it->fixupWithTLVStore->kind ) {
+                               case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
+                                       it->fixupWithTLVStore->kind = ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA;
+                                       break;
+                               case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad:
+                                       it->fixupWithTLVStore->kind = ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoadNowLEA;
+                                       break;
+                               case ld::Fixup::kindStoreX86PCRel32TLVLoad:
+                                       it->fixupWithTLVStore->kind = ld::Fixup::kindStoreX86PCRel32TLVLoadNowLEA;
+                                       break;
+                               case ld::Fixup::kindStoreX86Abs32TLVLoad:
+                                       it->fixupWithTLVStore->kind = ld::Fixup::kindStoreX86Abs32TLVLoadNowLEA;
+                                       break;
+                               default:
+                                       assert(0 && "bad store kind for TLV optimization");
+                       }
+               }
+               else {
+                       // change target to be new TLV pointer atom
+                       if (log) fprintf(stderr, "updating load of TLV to %s to load from TLV pointer\n", it->targetOfTLV->name());
+                       const ld::Atom* tlvpAtom = variableToPointerMap[it->targetOfTLV];
+                       assert(tlvpAtom != NULL);
+                       it->fixupWithTarget->binding = ld::Fixup::bindingDirectlyBound;
+                       it->fixupWithTarget->u.target = tlvpAtom;
+               }
+       }
+       
+       
+       
+       // alter tlv definitions to have an offset as third field
+       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::typeTLVDefs ) 
+                       continue;
+               for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin();  ait != sect->atoms.end(); ++ait) {
+                       const ld::Atom* atom = *ait;
+                       for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+                               if ( fit->offsetInAtom != 0 ) {
+                                       assert(fit->binding == ld::Fixup::bindingDirectlyBound && "thread variable def contains pointer to global");
+                                       switch( fit->u.target->contentType() ) {
+                                               case ld::Atom::typeTLVZeroFill:
+                                               case ld::Atom::typeTLVInitialValue:
+                                                       switch ( fit->kind ) {
+                                                               case ld::Fixup::kindSetTargetAddress:
+                                                                       fit->kind = ld::Fixup::kindSetTargetTLVTemplateOffset;
+                                                                       break;
+                                                               case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+                                                                       fit->kind = ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian32;
+                                                                       break;
+                                                               case ld::Fixup::kindStoreTargetAddressLittleEndian64:
+                                                                       fit->kind = ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian64;
+                                                                       break;
+                                                               default:
+                                                                       assert(0 && "bad kind for target in tlv defs");
+                                                                       break;
+                                                       }
+                                                       break;
+                                               default:
+                                                       assert(0 && "wrong content type for target in tlv defs");
+                                                       break;
+                                       }
+                               }
+                       }
+               }
+       }
+       
+}
+
+
+
+} // namespace tlvp
+} // namespace passes 
+} // namespace ld 
diff --git a/src/ld/passes/tlvp.h b/src/ld/passes/tlvp.h
new file mode 100644 (file)
index 0000000..0bb8786
--- /dev/null
@@ -0,0 +1,45 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#ifndef __TLVP_H__
+#define __TLVP_H__
+
+#include "Options.h"
+#include "ld.hpp"
+
+
+namespace ld {
+namespace passes {
+namespace tlvp {
+
+// called by linker to create TLVP entries and optimize TLV loads into LEAs instead
+extern void doPass(const Options& opts, ld::Internal& internal);
+
+
+} // namespace tlvp
+} // namespace passes 
+} // namespace ld 
+
+#endif // __TLVP_H__
index 25352b1b3b9cf066f8c184082bc6fbf0d22cf65a..abf716213f3b816b6376c5299aae1fa89b6ecbc5 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
  *
- * Copyright (c) 2005-2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #include <sys/stat.h>
 #include <sys/mman.h>
 #include <fcntl.h>
-#include <fcntl.h>
-
-#include "MachOReaderRelocatable.hpp"
+#include <mach-o/nlist.h>
+#include <mach-o/stab.h>
+#include <mach-o/fat.h>
+#include <mach-o/loader.h>
 
-#define LTO_SUPPORT 1
-
-#if LTO_SUPPORT
-       #include "LTOReader.hpp"
-#endif
+#include "MachOFileAbstraction.hpp"
+#include "parsers/macho_relocatable_file.h"
+#include "parsers/lto_file.h"
 
 static bool                    sDumpContent= true;
 static bool                    sDumpStabs      = false;
 static bool                    sSort           = true;
 static bool                    sNMmode         = false;
+static bool                    sShowSection                    = true;
+static bool                    sShowDefinitionKind             = true;
+static bool                    sShowCombineKind                = true;
+
 static cpu_type_t              sPreferredArch = CPU_TYPE_I386;
 static cpu_subtype_t   sPreferredSubArch = 0xFFFFFFFF;
-static const char* sMatchName;
+static const char* sMatchName = NULL;
 static int sPrintRestrict;
 static int sPrintAlign;
 static int sPrintName;
 
-
  __attribute__((noreturn))
 void throwf(const char* format, ...) 
 {
@@ -71,12 +73,12 @@ void warning(const char* format, ...)
        fprintf(stderr, "\n");
 }
 
-static void dumpStabs(std::vector<ObjectFile::Reader::Stab>* stabs)
+static void dumpStabs(const std::vector<ld::relocatable::File::Stab>* stabs)
 {
        // debug info
        printf("stabs: (%lu)\n", stabs->size());
-       for (std::vector<ObjectFile::Reader::Stab>::iterator it = stabs->begin(); it != stabs->end(); ++it ) {
-               ObjectFile::Reader::Stab& stab = *it;
+       for (std::vector<ld::relocatable::File::Stab>::const_iterator it = stabs->begin(); it != stabs->end(); ++it ) {
+               const ld::relocatable::File::Stab& stab = *it;
                const char* code = "?????";
                switch (stab.type) {
                        case N_GSYM:
@@ -164,24 +166,24 @@ static void dumpStabs(std::vector<ObjectFile::Reader::Stab>* stabs)
                                code =  "LENG";
                                break;
                }
-               printf("  [atom=%20s] %02X %04X %s %s\n", ((stab.atom != NULL) ? stab.atom->getDisplayName() : ""), stab.other, stab.desc, code, stab.string);
+               printf("  [atom=%20s] %02X %04X %s %s\n", ((stab.atom != NULL) ? stab.atom->name() : ""), stab.other, stab.desc, code, stab.string);
        }
 }
 
-
-static void dumpAtomLikeNM(ObjectFile::Atom* atom)
+#if 0
+static void dumpAtomLikeNM(ld::Atom* atom)
 {
-       uint32_t size = atom->getSize();
+       uint32_t size = atom->size();
        
        const char* visibility;
-       switch ( atom->getScope() ) {
-               case ObjectFile::Atom::scopeTranslationUnit:
+       switch ( atom->scope() ) {
+               case ld::Atom::scopeTranslationUnit:
                        visibility = "internal";
                        break;
-               case ObjectFile::Atom::scopeLinkageUnit:
+               case ld::Atom::scopeLinkageUnit:
                        visibility = "hidden  ";
                        break;
-               case ObjectFile::Atom::scopeGlobal:
+               case ld::Atom::scopeGlobal:
                        visibility = "global  ";
                        break;
                default:
@@ -190,17 +192,17 @@ static void dumpAtomLikeNM(ObjectFile::Atom* atom)
        }
 
        const char* kind;
-       switch ( atom->getDefinitionKind() ) {
-               case ObjectFile::Atom::kRegularDefinition:
+       switch ( atom->definitionKind() ) {
+               case ld::Atom::kRegularDefinition:
                        kind = "regular  ";
                        break;
-               case ObjectFile::Atom::kTentativeDefinition:
+               case ld::Atom::kTentativeDefinition:
                        kind = "tentative";
                        break;
-               case ObjectFile::Atom::kWeakDefinition:
+               case ld::Atom::kWeakDefinition:
                        kind = "weak     ";
                        break;
-               case ObjectFile::Atom::kAbsoluteSymbol:
+               case ld::Atom::kAbsoluteSymbol:
                        kind = "absolute ";
                        break;
                default:
@@ -208,31 +210,31 @@ static void dumpAtomLikeNM(ObjectFile::Atom* atom)
                        break;
        }
 
-       printf("0x%08X %s %s %s\n", size, visibility, kind, atom->getDisplayName());
+       printf("0x%08X %s %s %s\n", size, visibility, kind, atom->name());
 }
 
 
-static void dumpAtom(ObjectFile::Atom* atom)
+static void dumpAtom(ld::Atom* atom)
 {
-       if(sMatchName && strcmp(sMatchName, atom->getDisplayName()))
+       if(sMatchName && strcmp(sMatchName, atom->name()))
                return;
 
        //printf("atom:    %p\n", atom);
        
        // name
        if(!sPrintRestrict || sPrintName)
-               printf("name:    %s\n",  atom->getDisplayName());
+               printf("name:    %s\n",  atom->name());
        
        // scope
        if(!sPrintRestrict)
-               switch ( atom->getScope() ) {
-               case ObjectFile::Atom::scopeTranslationUnit:
+               switch ( atom->scope() ) {
+               case ld::Atom::scopeTranslationUnit:
                        printf("scope:   translation unit\n");
                        break;
-               case ObjectFile::Atom::scopeLinkageUnit:
+               case ld::Atom::scopeLinkageUnit:
                        printf("scope:   linkage unit\n");
                        break;
-               case ObjectFile::Atom::scopeGlobal:
+               case ld::Atom::scopeGlobal:
                        printf("scope:   global\n");
                        break;
                default:
@@ -241,23 +243,23 @@ static void dumpAtom(ObjectFile::Atom* atom)
        
        // kind
        if(!sPrintRestrict)
-               switch ( atom->getDefinitionKind() ) {
-               case ObjectFile::Atom::kRegularDefinition:
+               switch ( atom->definitionKind() ) {
+               case ld::Atom::kRegularDefinition:
                        printf("kind:     regular\n");
                        break;
-               case ObjectFile::Atom::kWeakDefinition:
+               case ld::Atom::kWeakDefinition:
                        printf("kind:     weak\n");
                        break;
-               case ObjectFile::Atom::kTentativeDefinition:
+               case ld::Atom::kTentativeDefinition:
                        printf("kind:     tentative\n");
                        break;
-               case ObjectFile::Atom::kExternalDefinition:
+               case ld::Atom::kExternalDefinition:
                        printf("kind:     import\n");
                        break;
-               case ObjectFile::Atom::kExternalWeakDefinition:
+               case ld::Atom::kExternalWeakDefinition:
                        printf("kind:     weak import\n");
                        break;
-               case ObjectFile::Atom::kAbsoluteSymbol:
+               case ld::Atom::kAbsoluteSymbol:
                        printf("kind:     absolute symbol\n");
                        break;
                default:
@@ -265,16 +267,14 @@ static void dumpAtom(ObjectFile::Atom* atom)
                }
 
        // segment and section
-       if(!sPrintRestrict && (atom->getSectionName() != NULL) )
-               printf("section: %s,%s\n", atom->getSegment().getName(), atom->getSectionName());
+       if(!sPrintRestrict && (atom->section().sectionName() != NULL) )
+               printf("section: %s,%s\n", atom->section().segmentName(), atom->section().sectionName());
 
        // attributes
        if(!sPrintRestrict) {
                printf("attrs:   ");
                if ( atom->dontDeadStrip() )
                        printf("dont-dead-strip ");
-               if ( atom->isZeroFill() )
-                       printf("zero-fill ");
                if ( atom->isThumb() )
                        printf("thumb ");
                printf("\n");
@@ -282,20 +282,20 @@ static void dumpAtom(ObjectFile::Atom* atom)
        
        // size
        if(!sPrintRestrict)
-               printf("size:    0x%012llX\n", atom->getSize());
+               printf("size:    0x%012llX\n", atom->size());
        
        // alignment
        if(!sPrintRestrict || sPrintAlign)
-               printf("align:    %u mod %u\n", atom->getAlignment().modulus, (1 << atom->getAlignment().powerOf2) );
+               printf("align:    %u mod %u\n", atom->alignment().modulus, (1 << atom->alignment().powerOf2) );
 
        // content
        if (!sPrintRestrict && sDumpContent ) { 
-               uint64_t size = atom->getSize();
+               uint64_t size = atom->size();
                if ( size < 4096 ) {
                        uint8_t content[size];
                        atom->copyRawContent(content);
                        printf("content: ");
-                       if ( atom->getContentType() == ObjectFile::Atom::kCStringType ) {
+                       if ( atom->contentType() == ld::Atom::typeCString ) {
                                printf("\"");
                                for (unsigned int i=0; i < size; ++i) {
                                        if(content[i]<'!' || content[i]>=127)
@@ -317,12 +317,12 @@ static void dumpAtom(ObjectFile::Atom* atom)
        if(!sPrintRestrict) {
                if ( atom->beginUnwind() != atom->endUnwind() ) {
                        printf("unwind encodings:\n");
-                       for (ObjectFile::UnwindInfo::iterator it = atom->beginUnwind(); it != atom->endUnwind(); ++it) {
+                       for (ld::Atom::UnwindInfo::iterator it = atom->beginUnwind(); it != atom->endUnwind(); ++it) {
                                printf("\t 0x%04X  0x%08X\n", it->startOffset, it->unwindInfo);
                        }
                }
        }
-       
+#if 0  
        // references
        if(!sPrintRestrict) {
                std::vector<ObjectFile::Reference*>&  references = atom->getReferences();
@@ -333,13 +333,12 @@ static void dumpAtom(ObjectFile::Atom* atom)
                        printf("   %s\n", ref->getDescription());
                }
        }
-       
+#endif 
        // line info
        if(!sPrintRestrict) {
-               std::vector<ObjectFile::LineInfo>* lineInfo = atom->getLineInfo();
-               if ( (lineInfo != NULL) && (lineInfo->size() > 0) ) {
-                       printf("line info: (%lu)\n", lineInfo->size());
-                       for (std::vector<ObjectFile::LineInfo>::iterator it = lineInfo->begin(); it != lineInfo->end(); ++it) {
+               if ( atom->beginLineInfo() != atom->endLineInfo() ) {
+                       printf("line info:\n");
+                       for (ld::Atom::LineInfo::iterator it = atom->beginLineInfo(); it != atom->endLineInfo(); ++it) {
                                printf("   offset 0x%04X, line %d, file %s\n", it->atomOffset, it->lineNumber, it->fileName);
                        }
                }
@@ -348,31 +347,711 @@ static void dumpAtom(ObjectFile::Atom* atom)
        if(!sPrintRestrict)
                printf("\n");
 }
-
+#endif
 struct AtomSorter
 {
-     bool operator()(const ObjectFile::Atom* left, const ObjectFile::Atom* right)
+     bool operator()(const ld::Atom* left, const ld::Atom* right)
      {
                if ( left == right )
                        return false;
-               int name = strcmp(left->getDisplayName(), right->getDisplayName());
-               if ( name == 0 )
-                       return (left->getSize() < right->getSize());
-               else
-                       return ( name < 0);
+               // first sort by segment name
+               int diff = strcmp(left->section().segmentName(), right->section().segmentName());
+               if ( diff != 0 )
+                       return (diff > 0);
+               
+               // then sort by section name
+               diff = strcmp(left->section().sectionName(), right->section().sectionName());
+               if ( diff != 0 )
+                       return (diff < 0);
+               
+               // then sort by atom name
+               diff = strcmp(left->name(), right->name());
+               if ( diff != 0 )
+                       return (diff < 0);
+               
+               // if cstring, sort by content
+               if ( left->contentType() == ld::Atom::typeCString ) {
+                       diff = strcmp((char*)left->rawContentPointer(), (char*)right->rawContentPointer());
+                       if ( diff != 0 )
+                               return (diff < 0);
+               }
+               else if ( left->section().type() == ld::Section::typeCStringPointer ) {
+                       // if pointer to c-string sort by name
+                       const char* leftString = NULL;
+                       assert(left->fixupsBegin() != left->fixupsEnd());
+                       for (ld::Fixup::iterator fit = left->fixupsBegin(); fit != left->fixupsEnd(); ++fit) {
+                               if ( fit->binding == ld::Fixup::bindingByContentBound ) {
+                                       const ld::Atom* cstringAtom = fit->u.target;
+                                       assert(cstringAtom->contentType() == ld::Atom::typeCString);
+                                       leftString = (char*)cstringAtom->rawContentPointer();
+                               }
+                       }
+                       const char* rightString = NULL;
+                       assert(right->fixupsBegin() != right->fixupsEnd());
+                       for (ld::Fixup::iterator fit = right->fixupsBegin(); fit != right->fixupsEnd(); ++fit) {
+                               if ( fit->binding == ld::Fixup::bindingByContentBound ) {
+                                       const ld::Atom* cstringAtom = fit->u.target;
+                                       assert(cstringAtom->contentType() == ld::Atom::typeCString);
+                                       rightString = (char*)cstringAtom->rawContentPointer();
+                               }
+                       }
+                       assert(leftString != NULL);
+                       assert(rightString != NULL);
+                       diff = strcmp(leftString, rightString);
+                       if ( diff != 0 )
+                               return (diff < 0);
+               }
+               else if ( left->section().type() == ld::Section::typeLiteral4 ) {
+                       // if literal sort by content
+                       uint32_t leftValue  = *(uint32_t*)left->rawContentPointer();
+                       uint32_t rightValue = *(uint32_t*)right->rawContentPointer();
+                       diff = (leftValue - rightValue);
+                       if ( diff != 0 )
+                               return (diff < 0);
+               }
+               else if ( left->section().type() == ld::Section::typeCFI ) {
+                       // if __he_frame sort by address
+                       diff = (left->objectAddress() - right->objectAddress());
+                       if ( diff != 0 )
+                               return (diff < 0);
+               }
+               else if ( left->section().type() == ld::Section::typeNonLazyPointer ) {
+                       // if non-lazy-pointer sort by name
+                       const char* leftString = NULL;
+                       assert(left->fixupsBegin() != left->fixupsEnd());
+                       for (ld::Fixup::iterator fit = left->fixupsBegin(); fit != left->fixupsEnd(); ++fit) {
+                               if ( fit->binding == ld::Fixup::bindingByNameUnbound ) {
+                                       leftString = fit->u.name;
+                               }
+                               else if ( fit->binding == ld::Fixup::bindingDirectlyBound ) {
+                                       leftString = fit->u.target->name();
+                               }
+                       }
+                       const char* rightString = NULL;
+                       assert(right->fixupsBegin() != right->fixupsEnd());
+                       for (ld::Fixup::iterator fit = right->fixupsBegin(); fit != right->fixupsEnd(); ++fit) {
+                               if ( fit->binding == ld::Fixup::bindingByNameUnbound ) {
+                                       rightString = fit->u.name;
+                               }
+                               else if ( fit->binding == ld::Fixup::bindingDirectlyBound ) {
+                                       rightString = fit->u.target->name();
+                               }
+                       }
+                       assert(leftString != NULL);
+                       assert(rightString != NULL);
+                       diff = strcmp(leftString, rightString);
+                       if ( diff != 0 )
+                               return (diff < 0);
+               }
+               
+               // else sort by size
+               return (left->size() < right->size());
      }
 };
 
 
-static void dumpFile(ObjectFile::Reader* reader)
+class dumper : public ld::File::AtomHandler
+{
+public:
+                       void dump();
+       virtual void doAtom(const ld::Atom&);
+       virtual void doFile(const ld::File&) {} 
+private:
+       void                    dumpAtom(const ld::Atom& atom);
+       const char*             scopeString(const ld::Atom&);
+       const char*             definitionString(const ld::Atom&);
+       const char*             combineString(const ld::Atom&);
+       const char*             inclusionString(const ld::Atom&);
+       const char*             attributeString(const ld::Atom&);
+       const char*             makeName(const ld::Atom& atom);
+       const char*             referenceTargetAtomName(const ld::Fixup* ref);
+       void                    dumpFixup(const ld::Fixup* ref);
+       
+       uint64_t                addressOfFirstAtomInSection(const ld::Section&);
+       
+       std::vector<const ld::Atom*> _atoms;
+};
+
+const char*    dumper::scopeString(const ld::Atom& atom)
+{
+       switch ( (ld::Atom::Scope)atom.scope() ) {
+               case ld::Atom::scopeTranslationUnit:
+                       return "translation-unit";
+               case ld::Atom::scopeLinkageUnit:
+                       return "hidden";
+               case ld::Atom::scopeGlobal:
+                       if ( atom.autoHide() )
+                               return "global but automatically hidden";
+                       else
+                               return "global";
+       }
+       return "UNKNOWN";       
+}
+
+const char*    dumper::definitionString(const ld::Atom& atom)
+{
+       switch ( (ld::Atom::Definition)atom.definition() ) {
+               case ld::Atom::definitionRegular:
+                       return "regular";
+               case ld::Atom::definitionTentative:
+                       return "tentative";
+               case ld::Atom::definitionAbsolute:
+                       return "absolute";
+               case ld::Atom::definitionProxy:
+                       return "proxy";
+               }
+       return "UNKNOWN";       
+}
+
+const char*    dumper::combineString(const ld::Atom& atom)
+{
+       switch ( (ld::Atom::Combine)atom.combine() ) {
+               case ld::Atom::combineNever:
+                       return "never";
+               case ld::Atom::combineByName:
+                       return "by-name";
+               case ld::Atom::combineByNameAndContent:
+                       return "by-name-and-content";
+               case ld::Atom::combineByNameAndReferences:
+                       return "by-name-and-references";
+               }
+       return "UNKNOWN";       
+}
+
+const char*    dumper::inclusionString(const ld::Atom& atom)
+{
+       switch ( (ld::Atom::SymbolTableInclusion)atom.symbolTableInclusion() ) {
+               case ld::Atom::symbolTableNotIn:
+                       return "not in";
+               case ld::Atom::symbolTableNotInFinalLinkedImages:
+                       return "not in final linked images";
+               case ld::Atom::symbolTableIn:
+                       return "in";
+               case ld::Atom::symbolTableInAndNeverStrip:
+                       return "in and never strip";
+               case ld::Atom::symbolTableInAsAbsolute:
+                       return "in as absolute";
+               case ld::Atom::symbolTableInWithRandomAutoStripLabel:
+                       return "in as random auto-strip label";
+               }
+       return "UNKNOWN";       
+}
+
+
+
+const char*    dumper::attributeString(const ld::Atom& atom)
+{
+       static char buffer[256];
+       buffer[0] = '\0';
+       
+       if ( atom.dontDeadStrip() )
+               strcat(buffer, "dont-dead-strip ");
+
+       if ( atom.isThumb() )
+               strcat(buffer, "thumb ");
+               
+       if ( atom.isAlias() )
+               strcat(buffer, "alias ");
+               
+       if ( atom.contentType() == ld::Atom::typeResolver )
+               strcat(buffer, "resolver ");
+               
+       return buffer;
+}
+
+const char* dumper::makeName(const ld::Atom& atom)
+{
+       static char buffer[4096];
+       strcpy(buffer, "???");
+       switch ( atom.symbolTableInclusion() ) {
+               case ld::Atom::symbolTableNotIn:
+                       if ( atom.contentType() == ld::Atom::typeCString ) {
+                               strcpy(buffer, "cstring=");
+                               strlcat(buffer, (char*)atom.rawContentPointer(), 4096);
+                       }
+                       else if ( atom.section().type() == ld::Section::typeLiteral4 ) {
+                               char temp[16];
+                               strcpy(buffer, "literal4=");
+                               uint32_t value = *(uint32_t*)atom.rawContentPointer();
+                               sprintf(temp, "0x%08X", value);
+                               strcat(buffer, temp);
+                       }
+                       else if ( atom.section().type() == ld::Section::typeLiteral8 ) {
+                               char temp[32];
+                               strcpy(buffer, "literal8=");
+                               uint32_t value1 = *(uint32_t*)atom.rawContentPointer();
+                               uint32_t value2 = ((uint32_t*)atom.rawContentPointer())[1];
+                               sprintf(temp, "0x%08X%08X", value1, value2);
+                               strcat(buffer, temp);
+                       }
+                       else if ( atom.section().type() == ld::Section::typeLiteral16 ) {
+                               char temp[64];
+                               strcpy(buffer, "literal16=");
+                               uint32_t value1 = *(uint32_t*)atom.rawContentPointer();
+                               uint32_t value2 = ((uint32_t*)atom.rawContentPointer())[1];
+                               uint32_t value3 = ((uint32_t*)atom.rawContentPointer())[2];
+                               uint32_t value4 = ((uint32_t*)atom.rawContentPointer())[3];
+                               sprintf(temp, "0x%08X%08X%08X%08X", value1, value2, value3, value4);
+                               strcat(buffer, temp);
+                       }
+                       else if ( atom.section().type() == ld::Section::typeCStringPointer ) {
+                               assert(atom.fixupsBegin() != atom.fixupsEnd());
+                               for (ld::Fixup::iterator fit = atom.fixupsBegin(); fit != atom.fixupsEnd(); ++fit) {
+                                       if ( fit->binding == ld::Fixup::bindingByContentBound ) {
+                                               const ld::Atom* cstringAtom = fit->u.target;
+                                               if ( (cstringAtom != NULL) && (cstringAtom->contentType() == ld::Atom::typeCString) ) {
+                                                       strlcpy(buffer, atom.name(), 4096);
+                                                       strlcat(buffer, "=", 4096);
+                                                       strlcat(buffer, (char*)cstringAtom->rawContentPointer(), 4096);
+                                               }
+                                       }
+                               }
+                       }
+                       else if ( atom.section().type() == ld::Section::typeNonLazyPointer ) {
+                               assert(atom.fixupsBegin() != atom.fixupsEnd());
+                               for (ld::Fixup::iterator fit = atom.fixupsBegin(); fit != atom.fixupsEnd(); ++fit) {
+                                       if ( fit->binding == ld::Fixup::bindingByNameUnbound ) {
+                                               strcpy(buffer, "non-lazy-pointer-to:");
+                                               strlcat(buffer, fit->u.name, 4096);
+                                               return buffer;
+                                       }
+                                       else if ( fit->binding == ld::Fixup::bindingDirectlyBound ) {
+                                               strcpy(buffer, "non-lazy-pointer-to-local:");
+                                               strlcat(buffer, fit->u.target->name(), 4096);
+                                               return buffer;
+                                       }
+                               }
+                               strlcpy(buffer, atom.name(), 4096);
+                       }
+                       else {
+                               uint64_t sectAddr = addressOfFirstAtomInSection(atom.section());
+                               sprintf(buffer, "%s@%s+0x%08llX", atom.name(), atom.section().sectionName(), atom.objectAddress()-sectAddr);
+                       }
+                       break;
+               case ld::Atom::symbolTableNotInFinalLinkedImages:
+               case ld::Atom::symbolTableIn:
+               case ld::Atom::symbolTableInAndNeverStrip:
+               case ld::Atom::symbolTableInAsAbsolute:
+               case ld::Atom::symbolTableInWithRandomAutoStripLabel:
+                       strlcpy(buffer, atom.name(), 4096);
+                       break;
+       }
+       return buffer;
+}
+
+const char* dumper::referenceTargetAtomName(const ld::Fixup* ref)
+{
+       static char buffer[4096];
+       switch ( ref->binding ) {
+               case ld::Fixup::bindingNone:
+                       return "NO BINDING";
+               case ld::Fixup::bindingByNameUnbound:
+                       strcpy(buffer, "by-name(");
+                       strlcat(buffer, ref->u.name, 4096);
+                       strlcat(buffer, ")", 4096);
+                       return buffer;
+                       //return ref->u.name;
+               case ld::Fixup::bindingByContentBound:
+                       strcpy(buffer, "by-content(");
+                       strlcat(buffer, makeName(*ref->u.target), 4096);
+                       strlcat(buffer, ")", 4096);
+                       return buffer;
+               case ld::Fixup::bindingDirectlyBound:
+                       strcpy(buffer, "direct(");
+                       strlcat(buffer, makeName(*ref->u.target), 4096);
+                       strlcat(buffer, ")", 4096);
+                       return buffer;
+               case ld::Fixup::bindingsIndirectlyBound:
+                       return "BOUND INDIRECTLY";
+       }
+       return "BAD BINDING";
+}
+
+
+void dumper::dumpFixup(const ld::Fixup* ref)
+{
+       if ( ref->weakImport ) {
+               printf("weak_import ");
+       }
+       switch ( (ld::Fixup::Kind)(ref->kind) ) {
+               case ld::Fixup::kindNone:
+                       printf("none");
+                       break;
+               case ld::Fixup::kindNoneFollowOn:
+                       printf("followed by %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindNoneGroupSubordinate:
+                       printf("group subordinate %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindNoneGroupSubordinateFDE:
+                       printf("group subordinate FDE %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindNoneGroupSubordinateLSDA:
+                       printf("group subordinate LSDA %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindNoneGroupSubordinatePersonality:
+                       printf("group subordinate personality %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindSetTargetAddress:
+                       printf("%s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindSubtractTargetAddress:
+                       printf(" - %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindAddAddend:
+                       printf(" + 0x%llX", ref->u.addend);
+                       break;
+               case ld::Fixup::kindSubtractAddend:
+                       printf(" - 0x%llX", ref->u.addend);
+                       break;
+               case ld::Fixup::kindSetTargetImageOffset:
+                       printf("imageOffset(%s)", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindSetTargetSectionOffset:
+                       printf("sectionOffset(%s)", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStore8:
+                       printf(", then store byte");
+                       break;
+               case ld::Fixup::kindStoreLittleEndian16:
+                       printf(", then store 16-bit little endian");
+                       break;
+               case ld::Fixup::kindStoreLittleEndianLow24of32:
+                       printf(", then store low 24-bit little endian");
+                       break;
+               case ld::Fixup::kindStoreLittleEndian32:
+                       printf(", then store 32-bit little endian");
+                       break;
+               case ld::Fixup::kindStoreLittleEndian64:
+                       printf(", then store 64-bit little endian");
+                       break;
+               case ld::Fixup::kindStoreBigEndian16:
+                       printf(", then store 16-bit big endian");
+                       break;
+               case ld::Fixup::kindStoreBigEndianLow24of32:
+                       printf(", then store low 24-bit big endian");
+                       break;
+               case ld::Fixup::kindStoreBigEndian32:
+                       printf(", then store 32-bit big endian");
+                       break;
+               case ld::Fixup::kindStoreBigEndian64:
+                       printf(", then store 64-bit big endian");
+                       break;
+               case ld::Fixup::kindStorePPCBranch24:
+                       printf(", then store as PPC branch24");
+                       break;
+               case ld::Fixup::kindStorePPCBranch14:
+                       printf(", then store as PPC branch14");
+                       break;
+               case ld::Fixup::kindStorePPCPicLow14:
+                       printf(", then store as PPC low14 pic");
+                       break;
+               case ld::Fixup::kindStorePPCPicLow16:
+                       printf(", then store as PPC low14 pic");
+                       break;
+               case ld::Fixup::kindStorePPCPicHigh16AddLow:
+                       printf(", then store as PPC high16 pic");
+                       break;
+               case ld::Fixup::kindStorePPCAbsLow14:
+                       printf(", then store as PPC low14 abs");
+                       break;
+               case ld::Fixup::kindStorePPCAbsLow16:
+                       printf(", then store as PPC low14 abs");
+                       break;
+               case ld::Fixup::kindStorePPCAbsHigh16AddLow:
+                       printf(", then store as PPC high16 abs");
+                       break;
+               case ld::Fixup::kindStorePPCAbsHigh16:
+                       printf(", then store as PPC high16 abs, no carry");
+                       break;
+               case ld::Fixup::kindStoreX86BranchPCRel8:
+                       printf(", then store as x86 8-bit pcrel branch");
+                       break;
+               case ld::Fixup::kindStoreX86BranchPCRel32:
+                       printf(", then store as x86 32-bit pcrel branch");
+                       break;
+               case ld::Fixup::kindStoreX86PCRel8:
+                       printf(", then store as x86 8-bit pcrel");
+                       break;
+               case ld::Fixup::kindStoreX86PCRel16:
+                       printf(", then store as x86 16-bit pcrel");
+                       break;
+               case ld::Fixup::kindStoreX86PCRel32:
+                       printf(", then store as x86 32-bit pcrel");
+                       break;
+               case ld::Fixup::kindStoreX86PCRel32_1:
+                       printf(", then store as x86 32-bit pcrel from +1");
+                       break;
+               case ld::Fixup::kindStoreX86PCRel32_2:
+                       printf(", then store as x86 32-bit pcrel from +2");
+                       break;
+               case ld::Fixup::kindStoreX86PCRel32_4:
+                       printf(", then store as x86 32-bit pcrel from +4");
+                       break;
+               case ld::Fixup::kindStoreX86PCRel32GOTLoad:
+                       printf(", then store as x86 32-bit pcrel GOT load");
+                       break;
+               case ld::Fixup::kindStoreX86PCRel32GOTLoadNowLEA:
+                       printf(", then store as x86 32-bit pcrel GOT load -> LEA");
+                       break;
+               case ld::Fixup::kindStoreX86PCRel32GOT:
+                       printf(", then store as x86 32-bit pcrel GOT access");
+                       break;
+               case ld::Fixup::kindStoreX86PCRel32TLVLoad:
+                       printf(", then store as x86 32-bit pcrel TLV load");
+                       break;
+               case ld::Fixup::kindStoreX86PCRel32TLVLoadNowLEA:
+                       printf(", then store as x86 32-bit pcrel TLV load");
+                       break;
+               case ld::Fixup::kindStoreX86Abs32TLVLoad:
+                       printf(", then store as x86 32-bit absolute TLV load");
+                       break;
+               case ld::Fixup::kindStoreX86Abs32TLVLoadNowLEA:
+                       printf(", then store as x86 32-bit absolute TLV load -> LEA");
+                       break;
+               case ld::Fixup::kindStoreARMBranch24:
+                       printf(", then store as ARM 24-bit pcrel branch");
+                       break;
+               case ld::Fixup::kindStoreThumbBranch22:
+                       printf(", then store as Thumb 22-bit pcrel branch");
+                       break;
+               case ld::Fixup::kindStoreARMLoad12:
+                       printf(", then store as ARM 12-bit pcrel load");
+                       break;
+               case ld::Fixup::kindStoreARMLow16:
+                       printf(", then store low-16 in ARM movw");
+                       break;
+               case ld::Fixup::kindStoreARMHigh16:
+                       printf(", then store high-16 in ARM movt");
+                       break;
+               case ld::Fixup::kindStoreThumbLow16:
+                       printf(", then store low-16 in Thumb movw");
+                       break;
+               case ld::Fixup::kindStoreThumbHigh16:
+                       printf(", then store high-16 in Thumb movt");
+                       break;
+               case ld::Fixup::kindDtraceExtra:
+                       printf("dtrace static probe extra info");
+                       break;
+               case ld::Fixup::kindStoreX86DtraceCallSiteNop:
+                       printf("x86 dtrace static probe site");
+                       break;
+               case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
+                       printf("x86 dtrace static is-enabled site");
+                       break;
+               case ld::Fixup::kindStorePPCDtraceCallSiteNop:
+                       printf("ppc dtrace static probe site");
+                       break;
+               case ld::Fixup::kindStorePPCDtraceIsEnableSiteClear:
+                       printf("ppc dtrace static is-enabled site");
+                       break;
+               case ld::Fixup::kindStoreARMDtraceCallSiteNop:
+                       printf("ARM dtrace static probe site");
+                       break;
+               case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear:
+                       printf("ARM dtrace static is-enabled site");
+                       break;
+               case ld::Fixup::kindStoreThumbDtraceCallSiteNop:
+                       printf("Thumb dtrace static probe site");
+                       break;
+               case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
+                       printf("Thumb dtrace static is-enabled site");
+                       break;
+               case ld::Fixup::kindLazyTarget:
+                       printf("lazy reference to external symbol %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindSetLazyOffset:
+                       printf("offset of lazy binding info for %s", referenceTargetAtomName(ref));
+                       break;                  
+               case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+                       printf("store 32-bit little endian address of %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressLittleEndian64:
+                       printf("store 64-bit little endian address of %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressBigEndian32:
+                       printf("store 32-bit big endian address of %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressBigEndian64:
+                       printf("store 64-bit big endian address of %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressX86PCRel32:
+                       printf("x86 store 32-bit pc-rel address of %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
+                       printf("x86 store 32-bit pc-rel branch to %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
+                       printf("x86 store 32-bit pc-rel GOT load of %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
+                       printf("x86 store 32-bit pc-rel lea of %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
+                       printf("x86 store 32-bit pc-rel TLV load of %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA:
+                       printf("x86 store 32-bit pc-rel TLV lea of %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad:
+                       printf("x86 store 32-bit absolute TLV load of %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoadNowLEA:
+                       printf("x86 store 32-bit absolute TLV lea of %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressARMBranch24:
+                       printf("ARM store 24-bit pc-rel branch to %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressThumbBranch22:
+                       printf("Thumb store 22-bit pc-rel branch to %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressARMLoad12:
+                       printf("ARM store 12-bit pc-rel branch to %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressPPCBranch24:
+                       printf("PowerPC store 24-bit pc-rel load of %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindSetTargetTLVTemplateOffset:
+               case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian32:
+               case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian64:
+                       printf("tlv template offset of %s", referenceTargetAtomName(ref));
+               //default:
+               //      printf("unknown fixup");
+               //      break;
+       }
+}
+
+uint64_t dumper::addressOfFirstAtomInSection(const ld::Section& sect)
+{
+       uint64_t lowestAddr = (uint64_t)(-1);
+       for (std::vector<const ld::Atom*>::iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
+               const ld::Atom* atom = *it;
+               if ( &atom->section() == &sect ) {
+                       if ( atom->objectAddress() < lowestAddr )
+                               lowestAddr = atom->objectAddress();
+               }
+       }
+       return lowestAddr;
+}
+
+void dumper::doAtom(const ld::Atom& atom)
+{
+       if ( (sMatchName != NULL) && (strcmp(sMatchName, atom.name()) != 0) )
+               return;
+       _atoms.push_back(&atom);
+}
+
+void dumper::dump()
+{      
+       if ( sSort ) 
+               std::sort(_atoms.begin(), _atoms.end(), AtomSorter());
+
+       for (std::vector<const ld::Atom*>::iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
+               this->dumpAtom(**it);
+       }
+}      
+
+void dumper::dumpAtom(const ld::Atom& atom)
+{              
+       printf("name:     %s\n", makeName(atom)); 
+       printf("size:     0x%0llX\n", atom.size());
+       printf("align:    %u mod %u\n", atom.alignment().modulus, (1 << atom.alignment().powerOf2) );
+       printf("scope:    %s\n", scopeString(atom));
+       if ( sShowDefinitionKind ) 
+               printf("def:      %s\n", definitionString(atom));
+       if ( sShowCombineKind )
+               printf("combine:  %s\n", combineString(atom));
+       printf("symbol:   %s\n", inclusionString(atom));
+       printf("attrs:    %s\n", attributeString(atom));
+       if ( sShowSection )
+               printf("section:  %s,%s\n", atom.section().segmentName(), atom.section().sectionName());
+       if ( atom.beginUnwind() != atom.endUnwind() ) {
+               printf("unwind:   0x%08X\n", atom.beginUnwind()->unwindInfo);
+       }
+       if ( atom.contentType() == ld::Atom::typeCString ) {
+               uint8_t buffer[atom.size()+2];
+               atom.copyRawContent(buffer);
+               buffer[atom.size()] = '\0';
+               printf("content:  \"%s\"\n", buffer);
+       }
+       if ( atom.fixupsBegin() != atom.fixupsEnd() ) {
+               printf("fixups:\n");
+               for (unsigned int off=0; off < atom.size()+1; ++off) {
+                       for (ld::Fixup::iterator it = atom.fixupsBegin(); it != atom.fixupsEnd(); ++it) {
+                               if ( it->offsetInAtom == off ) {
+                                       switch ( it->clusterSize ) {
+                                               case ld::Fixup::k1of1:
+                                                       printf("    0x%04X ", it->offsetInAtom);
+                                                       dumpFixup(it);
+                                                       break;
+                                               case ld::Fixup::k1of2:
+                                                       printf("    0x%04X ", it->offsetInAtom);
+                                                       dumpFixup(it);
+                                                       ++it;
+                                                       dumpFixup(it);
+                                                       break;
+                                               case ld::Fixup::k1of3:
+                                                       printf("    0x%04X ", it->offsetInAtom);
+                                                       dumpFixup(it);
+                                                       ++it;
+                                                       dumpFixup(it);
+                                                       ++it;
+                                                       dumpFixup(it);
+                                                       break;
+                                               case ld::Fixup::k1of4:
+                                                       printf("    0x%04X ", it->offsetInAtom);
+                                                       dumpFixup(it);
+                                                       ++it;
+                                                       dumpFixup(it);
+                                                       ++it;
+                                                       dumpFixup(it);
+                                                       ++it;
+                                                       dumpFixup(it);
+                                                       break;
+                                               case ld::Fixup::k1of5:
+                                                       printf("    0x%04X ", it->offsetInAtom);
+                                                       dumpFixup(it);
+                                                       ++it;
+                                                       dumpFixup(it);
+                                                       ++it;
+                                                       dumpFixup(it);
+                                                       ++it;
+                                                       dumpFixup(it);
+                                                       ++it;
+                                                       dumpFixup(it);
+                                                       break;
+                                               default:
+                                                       printf("   BAD CLUSTER SIZE: cluster=%d\n", it->clusterSize);
+                                       }
+                                       printf("\n");
+                               }
+                       }
+               }
+       }
+       if ( atom.beginLineInfo() != atom.endLineInfo() ) {
+               printf("line info:\n");
+               for (ld::Atom::LineInfo::iterator it = atom.beginLineInfo(); it != atom.endLineInfo(); ++it) {
+                       printf("   offset 0x%04X, line %d, file %s\n", it->atomOffset, it->lineNumber, it->fileName);
+               }
+       }
+
+       printf("\n");
+}
+
+static void dumpFile(ld::relocatable::File* file)
 {
        // stabs debug info
-       if ( sDumpStabs && (reader->getDebugInfoKind() == ObjectFile::Reader::kDebugInfoStabs) ) {
-               std::vector<ObjectFile::Reader::Stab>* stabs = reader->getStabs();
+       if ( sDumpStabs && (file->debugInfo() == ld::relocatable::File::kDebugInfoStabs) ) {
+               const std::vector<ld::relocatable::File::Stab>* stabs = file->stabs();
                if ( stabs != NULL )
                        dumpStabs(stabs);
        }
-       
+       // dump atoms
+       dumper d;
+       file->forEachAtom(d);
+       d.dump();
+
+#if 0  
        // get all atoms
        std::vector<ObjectFile::Atom*> atoms = reader->getAtoms();
        
@@ -387,10 +1066,11 @@ static void dumpFile(ObjectFile::Reader* reader)
                else
                        dumpAtom(*it);
        }
+#endif
 }
 
 
-static ObjectFile::Reader* createReader(const char* path, const ObjectFile::ReaderOptions& options)
+static ld::relocatable::File* createReader(const char* path)
 {
        struct stat stat_buf;
        
@@ -400,7 +1080,11 @@ static ObjectFile::Reader* createReader(const char* path, const ObjectFile::Read
        ::fstat(fd, &stat_buf);
        uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
        ::close(fd);
+       if ( p == (uint8_t*)(-1) )
+               throwf("cannot mmap file: %s", path);
        const mach_header* mh = (mach_header*)p;
+       uint64_t fileLen = stat_buf.st_size;
+       bool foundFatSlice = false;
        if ( mh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
                const struct fat_header* fh = (struct fat_header*)p;
                const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
@@ -409,28 +1093,48 @@ static ObjectFile::Reader* createReader(const char* path, const ObjectFile::Read
                                if ( ((uint32_t)sPreferredSubArch == 0xFFFFFFFF) || ((uint32_t)sPreferredSubArch == OSSwapBigToHostInt32(archs[i].cpusubtype)) ) {
                                        p = p + OSSwapBigToHostInt32(archs[i].offset);
                                        mh = (struct mach_header*)p;
+                                       fileLen = OSSwapBigToHostInt32(archs[i].size);
+                                       foundFatSlice = true;
                                        break;
                                }
                        }
                }
        }
-       if ( mach_o::relocatable::Reader<x86>::validFile(p) )
-               return new mach_o::relocatable::Reader<x86>::Reader(p, path, 0, options, 0);
-       else if ( mach_o::relocatable::Reader<ppc>::validFile(p) )
-               return new mach_o::relocatable::Reader<ppc>::Reader(p, path, 0, options, 0);
-       else if ( mach_o::relocatable::Reader<ppc64>::validFile(p) )
-               return new mach_o::relocatable::Reader<ppc64>::Reader(p, path, 0, options, 0);
-       else if ( mach_o::relocatable::Reader<x86_64>::validFile(p) )
-               return new mach_o::relocatable::Reader<x86_64>::Reader(p, path, 0, options, 0);
-       else if ( mach_o::relocatable::Reader<arm>::validFile(p) )
-               return new mach_o::relocatable::Reader<arm>::Reader(p, path, 0, options, 0);
-#if LTO_SUPPORT
-       if ( lto::Reader::validFile(p, stat_buf.st_size, 0) ) {
-               return new lto::Reader(p, stat_buf.st_size, path, 0, options, 0);
+
+       mach_o::relocatable::ParserOptions objOpts;
+       objOpts.architecture            = sPreferredArch;
+       objOpts.objSubtypeMustMatch = false;
+       objOpts.logAllFiles                     = false;
+       objOpts.convertUnwindInfo       = true;
+       objOpts.subType                         = sPreferredSubArch;
+#if 1
+       if ( ! foundFatSlice ) {
+               cpu_type_t archOfObj;
+               cpu_subtype_t subArchOfObj;
+               if ( mach_o::relocatable::isObjectFile(p, &archOfObj, &subArchOfObj) ) {
+                       objOpts.architecture = archOfObj;
+                       objOpts.subType = subArchOfObj;
+               }
        }
-#endif
-       
+
+       ld::relocatable::File* objResult = mach_o::relocatable::parse(p, fileLen, path, stat_buf.st_mtime, 0, 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);
+       if ( objResult != NULL ) 
+               return objResult;
+
        throwf("not a mach-o object file: %s", path);
+#else
+       // for peformance testing
+       for (int i=0; i < 500; ++i ) {
+               ld::relocatable::File* objResult = mach_o::relocatable::parse(p, fileLen, path, stat_buf.st_mtime, 0, objOpts);
+               delete objResult;
+       }
+       exit(0);
+#endif
 }
 
 static
@@ -439,6 +1143,9 @@ usage()
 {
        fprintf(stderr, "ObjectDump options:\n"
                        "\t-no_content\tdon't dump contents\n"
+                       "\t-no_section\tdon't dump section name\n"
+                       "\t-no_defintion\tdon't dump definition kind\n"
+                       "\t-no_combine\tdon't dump combine mode\n"
                        "\t-stabs\t\tdump stabs\n"
                        "\t-arch aaa\tonly dump info about arch aaa\n"
                        "\t-only sym\tonly dump info about sym\n"
@@ -454,8 +1161,6 @@ int main(int argc, const char* argv[])
                return 0;
        }
 
-       ObjectFile::ReaderOptions options;
-       options.fAddCompactUnwindEncoding = true;
        try {
                for(int i=1; i < argc; ++i) {
                        const char* arg = argv[i];
@@ -472,6 +1177,15 @@ int main(int argc, const char* argv[])
                                else if ( strcmp(arg, "-no_sort") == 0 ) {
                                        sSort = false;
                                }
+                               else if ( strcmp(arg, "-no_section") == 0 ) {
+                                       sShowSection = false;
+                               }
+                               else if ( strcmp(arg, "-no_definition") == 0 ) {
+                                       sShowDefinitionKind = false;
+                               }
+                               else if ( strcmp(arg, "-no_combine") == 0 ) {
+                                       sShowCombineKind = false;
+                               }
                                else if ( strcmp(arg, "-arch") == 0 ) {
                                        const char* arch = ++i<argc? argv[i]: "";
                                        if ( strcmp(arch, "ppc64") == 0 )
@@ -520,7 +1234,7 @@ int main(int argc, const char* argv[])
                                }
                        }
                        else {
-                               ObjectFile::Reader* reader = createReader(arg, options);
+                               ld::relocatable::File* reader = createReader(arg);
                                dumpFile(reader);
                        }
                }
index 5c4247139bacba654084ee19da8b7e943345c88c..a6988ec2179c0be42375b73d13df7a02763facb9 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
  *
- * Copyright (c) 2008-2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2008-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -46,12 +46,16 @@ static bool printLazyBind = false;
 static bool printOpcodes = false;
 static bool printExport = false;
 static bool printExportGraph = false;
+static bool printExportNodes = false;
+static bool printSharedRegion = false;
+static bool printFunctionStarts = false;
+static bool printDylibs = false;
 static cpu_type_t      sPreferredArch = CPU_TYPE_I386;
 static cpu_type_t      sPreferredSubArch = 0;
 
 
- __attribute__((noreturn))
-void throwf(const char* format, ...) 
+__attribute__((noreturn))
+static void throwf(const char* format, ...) 
 {
        va_list list;
        char*   p;
@@ -98,18 +102,25 @@ private:
        void                                                                            printLazyBindingOpcodes();
        void                                                                            printExportInfo();
        void                                                                            printExportInfoGraph();
+       void                                                                            printExportInfoNodes();
        void                                                                            printRelocRebaseInfo();
        void                                                                            printSymbolTableExportInfo();
        void                                                                            printClassicLazyBindingInfo();
        void                                                                            printClassicBindingInfo();
+       void                                                                            printSharedRegionInfo();
+       void                                                                            printFunctionStartsInfo();
+       void                                                                            printDylibsInfo();
+       void                                                                            printFunctionStartLine(uint64_t addr);
+       const uint8_t*                                                          printSharedRegionInfoForEachULEB128Address(const uint8_t* p, uint8_t kind);
        pint_t                                                                          relocBase();
        const char*                                                                     relocTypeName(uint8_t r_type);
        uint8_t                                                                         segmentIndexForAddress(pint_t addr);
-       void                                                                            processExportNode(const uint8_t* const start, const uint8_t* p, const uint8_t* const end, 
-                                                                                                                               char* cummulativeString, int curStrOffset);
        void                                                                            processExportGraphNode(const uint8_t* const start, const uint8_t* const end,  
                                                                                                                                        const uint8_t* parent, const uint8_t* p,
                                                                                                                                        char* cummulativeString, int curStrOffset);
+       void                                                                            gatherNodeStarts(const uint8_t* const start, const uint8_t* const end,  
+                                                                                                                               const uint8_t* parent, const uint8_t* p,
+                                                                                                                               std::vector<uint32_t>& nodeStarts);
        const char*                                                                     rebaseTypeName(uint8_t type);
        const char*                                                                     bindTypeName(uint8_t type);
        pint_t                                                                          segStartAddress(uint8_t segIndex);
@@ -119,7 +130,7 @@ private:
        const char*                                                                     ordinalName(int libraryOrdinal);
        const char*                                                                     classicOrdinalName(int libraryOrdinal);
        pint_t*                                                                         mappedAddressForVMAddress(pint_t vmaddress);
-
+       const char*                                                                     symbolNameForAddress(uint64_t);
 
                
        const char*                                                                     fPath;
@@ -130,6 +141,8 @@ private:
        const macho_nlist<P>*                                           fSymbols;
        uint32_t                                                                        fSymbolCount;
        const macho_dyld_info_command<P>*                       fInfo;
+       const macho_linkedit_data_command<P>*           fSharedRegionInfo;
+       const macho_linkedit_data_command<P>*           fFunctionStartsInfo;
        uint64_t                                                                        fBaseAddress;
        const macho_dysymtab_command<P>*                        fDynamicSymbolTable;
        const macho_segment_command<P>*                         fFirstSegment;
@@ -137,6 +150,7 @@ private:
        bool                                                                            fWriteableSegmentWithAddrOver4G;
        std::vector<const macho_segment_command<P>*>fSegments;
        std::vector<const char*>                                        fDylibs;
+       std::vector<const macho_dylib_command<P>*>      fDylibLoadCommands;
 };
 
 
@@ -235,6 +249,7 @@ template <typename A>
 DyldInfoPrinter<A>::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path)
  : fHeader(NULL), fLength(fileLength), 
    fStrings(NULL), fStringsEnd(NULL), fSymbols(NULL), fSymbolCount(0), fInfo(NULL), 
+   fSharedRegionInfo(NULL), fFunctionStartsInfo(NULL), 
    fBaseAddress(0), fDynamicSymbolTable(NULL), fFirstSegment(NULL), fFirstWritableSegment(NULL),
    fWriteableSegmentWithAddrOver4G(false)
 {
@@ -281,9 +296,11 @@ DyldInfoPrinter<A>::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLen
                        case LC_LOAD_DYLIB:
                        case LC_LOAD_WEAK_DYLIB:
                        case LC_REEXPORT_DYLIB:
+                       case LC_LOAD_UPWARD_DYLIB:
                        case LC_LAZY_LOAD_DYLIB:
                                {
                                const macho_dylib_command<P>* dylib  = (macho_dylib_command<P>*)cmd;
+                               fDylibLoadCommands.push_back(dylib);
                                const char* lastSlash = strrchr(dylib->name(), '/');
                                const char* leafName = (lastSlash != NULL) ? lastSlash+1 : dylib->name();
                                const char* firstDot = strchr(leafName, '.');
@@ -309,6 +326,12 @@ DyldInfoPrinter<A>::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLen
                                        fStringsEnd = fStrings + symtab->strsize();
                                }
                                break;
+                       case LC_SEGMENT_SPLIT_INFO:
+                               fSharedRegionInfo = (macho_linkedit_data_command<P>*)cmd;
+                               break;
+                       case LC_FUNCTION_STARTS:
+                               fFunctionStartsInfo = (macho_linkedit_data_command<P>*)cmd;
+                               break;
                }
                cmd = (const macho_load_command<P>*)endOfCmd;
        }
@@ -347,6 +370,14 @@ DyldInfoPrinter<A>::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLen
        }
        if ( printExportGraph )
                printExportInfoGraph();
+       if ( printExportNodes ) 
+               printExportInfoNodes();
+       if ( printSharedRegion )
+               printSharedRegionInfo();
+       if ( printFunctionStarts ) 
+               printFunctionStartsInfo();
+       if ( printDylibs )
+               printDylibsInfo();
 }
 
 static uint64_t read_uleb128(const uint8_t*& p, const uint8_t* end)
@@ -522,6 +553,8 @@ const char* DyldInfoPrinter<A>::ordinalName(int libraryOrdinal)
 template <typename A>
 const char* DyldInfoPrinter<A>::classicOrdinalName(int libraryOrdinal)
 {
+       if ( (fHeader->flags() & MH_TWOLEVEL) ==  0 )
+               return "flat-namespace";
        switch ( libraryOrdinal) {
                case SELF_LIBRARY_ORDINAL:
                        return "this-image";
@@ -811,7 +844,7 @@ void DyldInfoPrinter<A>::printBindingInfo()
        }
        else {
                printf("bind information:\n");
-               printf("segment section          address        type   weak  addend dylib            symbol\n");
+               printf("segment section          address        type    addend dylib            symbol\n");
                const uint8_t* p = (uint8_t*)fHeader + fInfo->bind_off();
                const uint8_t* end = &p[fInfo->bind_size()];
                
@@ -861,7 +894,7 @@ void DyldInfoPrinter<A>::printBindingInfo()
                                                ++p;
                                        ++p;
                                        if ( (immediate & BIND_SYMBOL_FLAGS_WEAK_IMPORT) != 0 )
-                                               weak_import = "weak";
+                                               weak_import = " (weak import)";
                                        else
                                                weak_import = "";
                                        break;
@@ -882,22 +915,22 @@ void DyldInfoPrinter<A>::printBindingInfo()
                                        segOffset += read_uleb128(p, end);
                                        break;
                                case BIND_OPCODE_DO_BIND:
-                                       printf("%-7s %-16s 0x%08llX %10s %4s  %5lld %-16s %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, weak_import, addend, fromDylib, symbolName );
+                                       printf("%-7s %-16s 0x%08llX %10s  %5lld %-16s %s%s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName, weak_import );
                                        segOffset += sizeof(pint_t);
                                        break;
                                case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
-                                       printf("%-7s %-16s 0x%08llX %10s %4s  %5lld %-16s %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, weak_import, addend, fromDylib, symbolName );
+                                       printf("%-7s %-16s 0x%08llX %10s  %5lld %-16s %s%s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName, weak_import );
                                        segOffset += read_uleb128(p, end) + sizeof(pint_t);
                                        break;
                                case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
-                                       printf("%-7s %-16s 0x%08llX %10s %4s  %5lld %-16s %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, weak_import, addend, fromDylib, symbolName );
+                                       printf("%-7s %-16s 0x%08llX %10s  %5lld %-16s %s%s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName, weak_import );
                                        segOffset += immediate*sizeof(pint_t) + sizeof(pint_t);
                                        break;
                                case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
                                        count = read_uleb128(p, end);
                                        skip = read_uleb128(p, end);
                                        for (uint32_t i=0; i < count; ++i) {
-                                               printf("%-7s %-16s 0x%08llX %10s %4s  %5lld %-16s %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, weak_import, addend, fromDylib, symbolName );
+                                               printf("%-7s %-16s 0x%08llX %10s  %5lld %-16s %s%s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName, weak_import );
                                                segOffset += skip + sizeof(pint_t);
                                        }
                                        break;
@@ -1019,6 +1052,7 @@ void DyldInfoPrinter<A>::printLazyBindingInfo()
                pint_t segStartAddr = 0;
                const char* segName = "??";
                const char* typeName = "??";
+               const char* weak_import = "";
                for (const uint8_t* p=start; p < end; ) {
                        uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
                        uint8_t opcode = *p & BIND_OPCODE_MASK;
@@ -1050,6 +1084,10 @@ void DyldInfoPrinter<A>::printLazyBindingInfo()
                                        while (*p != '\0')
                                                ++p;
                                        ++p;
+                                       if ( (immediate & BIND_SYMBOL_FLAGS_WEAK_IMPORT) != 0 )
+                                               weak_import = " (weak import)";
+                                       else
+                                               weak_import = "";
                                        break;
                                case BIND_OPCODE_SET_TYPE_IMM:
                                        type = immediate;
@@ -1068,7 +1106,7 @@ void DyldInfoPrinter<A>::printLazyBindingInfo()
                                        segOffset += read_uleb128(p, end);
                                        break;
                                case BIND_OPCODE_DO_BIND:
-                                       printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, lazy_offset, fromDylib, symbolName );
+                                       printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s%s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, lazy_offset, fromDylib, symbolName, weak_import);
                                        segOffset += sizeof(pint_t);
                                        break;
                                default:
@@ -1177,35 +1215,6 @@ void DyldInfoPrinter<A>::printLazyBindingOpcodes()
 
 }
 
-
-template <typename A>
-void DyldInfoPrinter<A>::processExportNode(const uint8_t* const start, const uint8_t* p, const uint8_t* const end, 
-                                                                                       char* cummulativeString, int curStrOffset) 
-{
-       const uint8_t terminalSize = *p++;
-       const uint8_t* children = p + terminalSize;
-       if ( terminalSize != 0 ) {
-               uint32_t flags = read_uleb128(p, end);
-               uint64_t address = read_uleb128(p, end);
-               if ( flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION )
-                       fprintf(stdout, "0x%08llX [weak_def] %s\n", address, cummulativeString);
-               else
-                       fprintf(stdout, "0x%08llX %s\n", address, cummulativeString);
-       }
-       const uint8_t childrenCount = *children++;
-       const uint8_t* s = children;
-       for (uint8_t i=0; i < childrenCount; ++i) {
-               int edgeStrLen = 0;
-               while (*s != '\0') {
-                       cummulativeString[curStrOffset+edgeStrLen] = *s++;
-                       ++edgeStrLen;
-               }
-               cummulativeString[curStrOffset+edgeStrLen] = *s++;
-               uint32_t childNodeOffet = read_uleb128(s, end);
-               processExportNode(start, start+childNodeOffet, end, cummulativeString, curStrOffset+edgeStrLen);        
-       }
-}
-
 struct SortExportsByAddress
 {
      bool operator()(const mach_o::trie::Entry& left, const mach_o::trie::Entry& right)
@@ -1228,10 +1237,26 @@ void DyldInfoPrinter<A>::printExportInfo()
                parseTrie(start, end, list);
                //std::sort(list.begin(), list.end(), SortExportsByAddress());
                for (std::vector<mach_o::trie::Entry>::iterator it=list.begin(); it != list.end(); ++it) {
-                       const char* flags = "";
-                       if ( it->flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION )
-                               flags = "[weak_def] ";
-                       fprintf(stdout, "0x%08llX %s%s\n", fBaseAddress+it->address, flags, it->name);
+                       if ( it->flags & EXPORT_SYMBOL_FLAGS_REEXPORT ) {
+                               if ( it->importName[0] == '\0' )
+                                       fprintf(stdout, "[re-export] %s from dylib=%llu\n", it->name, it->other);
+                               else
+                                       fprintf(stdout, "[re-export] %s from dylib=%llu named=%s\n", it->name, it->other, it->importName);
+                       }
+                       else {
+                               const char* flags = "";
+                               if ( it->flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION )
+                                       flags = "[weak_def] ";
+                               else if ( (it->flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL )
+                                       flags = "[per-thread] ";
+                               if ( it->flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER ) {
+                                       flags = "[resolver] ";
+                                       fprintf(stdout, "0x%08llX  %s%s (resolver=0x%08llX)\n", fBaseAddress+it->address, flags, it->name, it->other);
+                               }
+                               else {
+                                       fprintf(stdout, "0x%08llX  %s%s\n", fBaseAddress+it->address, flags, it->name);
+                               }
+                       }
                }
        }
 }
@@ -1243,13 +1268,27 @@ void DyldInfoPrinter<A>::processExportGraphNode(const uint8_t* const start, cons
                                                                                        char* cummulativeString, int curStrOffset) 
 {
        const uint8_t* const me = p;
-       const uint8_t terminalSize = *p++;
+       const uint8_t terminalSize = read_uleb128(p, end);
        const uint8_t* children = p + terminalSize;
        if ( terminalSize != 0 ) {
                uint32_t flags = read_uleb128(p, end);
-               (void)flags; // currently unused
-               uint64_t address = read_uleb128(p, end);
-               printf("\tnode%03ld [ label=%s,addr0x%08llX ];\n", (long)(me-start), cummulativeString, address);
+               if ( flags & EXPORT_SYMBOL_FLAGS_REEXPORT ) {
+                       uint64_t ordinal = read_uleb128(p, end);
+                       const char* importName = (const char*)p;
+                       while (*p != '\0')
+                               ++p;
+                       ++p;
+                       if ( *importName == '\0' ) 
+                               printf("\tnode%03ld [ label=%s,re-export from dylib=%llu ];\n", (long)(me-start), cummulativeString, ordinal);
+                       else
+                               printf("\tnode%03ld [ label=%s,re-export %s from dylib=%llu ];\n", (long)(me-start), cummulativeString, importName, ordinal);
+               }
+               else {
+                       uint64_t address = read_uleb128(p, end);
+                       printf("\tnode%03ld [ label=%s,addr0x%08llX ];\n", (long)(me-start), cummulativeString, address);
+                       if ( flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER )
+                               read_uleb128(p, end);
+               }
        }
        else {
                printf("\tnode%03ld;\n", (long)(me-start));
@@ -1286,6 +1325,222 @@ void DyldInfoPrinter<A>::printExportInfoGraph()
        }
 }
 
+template <typename A>
+void DyldInfoPrinter<A>::gatherNodeStarts(const uint8_t* const start, const uint8_t* const end,  
+                                                                                       const uint8_t* parent, const uint8_t* p,
+                                                                                       std::vector<uint32_t>& nodeStarts) 
+{
+       nodeStarts.push_back(p-start);
+       const uint8_t terminalSize = read_uleb128(p, end);
+       const uint8_t* children = p + terminalSize;
+       
+       const uint8_t childrenCount = *children++;
+       const uint8_t* s = children;
+       for (uint8_t i=0; i < childrenCount; ++i) {
+               // skip over edge string
+               while (*s != '\0')
+                       ++s;
+               ++s;
+               uint32_t childNodeOffet = read_uleb128(s, end);
+               gatherNodeStarts(start, end, start, start+childNodeOffet, nodeStarts);  
+       }
+}
+
+
+template <typename A>
+void DyldInfoPrinter<A>::printExportInfoNodes()
+{
+       if ( (fInfo == NULL) || (fInfo->export_off() == 0) ) {
+               printf("no compressed export info\n");
+       }
+       else {
+               const uint8_t* start = (uint8_t*)fHeader + fInfo->export_off();
+               const uint8_t* end = &start[fInfo->export_size()];
+               std::vector<uint32_t> nodeStarts;
+               gatherNodeStarts(start, end, start, start, nodeStarts);
+               std::sort(nodeStarts.begin(), nodeStarts.end());
+               for (std::vector<uint32_t>::const_iterator it=nodeStarts.begin(); it != nodeStarts.end(); ++it) {
+                       printf("0x%04X: ", *it);
+                       const uint8_t* p = start + *it;
+                       uint64_t exportInfoSize = read_uleb128(p, end);
+                       if ( exportInfoSize != 0 ) {
+                               // print terminal info
+                               uint64_t flags = read_uleb128(p, end);
+                               if ( flags & EXPORT_SYMBOL_FLAGS_REEXPORT ) {
+                                       uint64_t ordinal = read_uleb128(p, end);
+                                       const char* importName = (const char*)p;
+                                       while (*p != '\0')
+                                               ++p;
+                                       ++p;
+                                       if ( strlen(importName) == 0 )
+                                               printf("[flags=REEXPORT ordinal=%llu] ", ordinal);
+                                       else
+                                               printf("[flags=REEXPORT ordinal=%llu import=%s] ", ordinal, importName);
+                               }
+                               else if ( flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER ) {
+                                       uint64_t stub = read_uleb128(p, end);
+                                       uint64_t resolver = read_uleb128(p, end);
+                                       printf("[flags=STUB_AND_RESOLVER stub=0x%06llX resolver=0x%06llX] ", stub, resolver);
+                               }
+                               else {
+                                       uint64_t address = read_uleb128(p, end);
+                                       if ( (flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_REGULAR )
+                                               printf("[addr=0x%06llX] ", address);
+                                       else if ( (flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL)
+                                               printf("[flags=THREAD_LOCAL addr=0x%06llX] ", address);
+                                       else
+                                               printf("[flags=0x%llX addr=0x%06llX] ", flags, address);
+                               }
+                       }
+                       // print child edges
+                       const uint8_t childrenCount = *p++;
+                       for (uint8_t i=0; i < childrenCount; ++i) {
+                               const char* edgeName = (const char*)p;
+                               while (*p != '\0')
+                                       ++p;
+                               ++p;
+                               uint32_t childNodeOffet = read_uleb128(p, end);
+                               printf("%s->0x%04X", edgeName, childNodeOffet);
+                               if ( i < (childrenCount-1) )
+                                       printf(", ");
+                       }
+                       printf("\n");
+               }
+       }
+}
+
+
+
+template <typename A>
+const uint8_t* DyldInfoPrinter<A>::printSharedRegionInfoForEachULEB128Address(const uint8_t* p, uint8_t kind)
+{
+       const char* kindStr =  "??";
+       switch (kind) {
+               case 1:
+                       kindStr = "32-bit pointer";
+                       break;
+               case 2:
+                       kindStr = "64-bit pointer";
+                       break;
+               case 3:
+                       kindStr = "ppc hi16";
+                       break;
+               case 4:
+                       kindStr = "32-bit offset to IMPORT";
+                       break;
+       }
+       uint64_t address = 0;
+       uint64_t delta = 0;
+       uint32_t shift = 0;
+       bool more = true;
+       do {
+               uint8_t byte = *p++;
+               delta |= ((byte & 0x7F) << shift);
+               shift += 7;
+               if ( byte < 0x80 ) {
+                       if ( delta != 0 ) {
+                               address += delta;
+                               printf("0x%0llX   %s\n", address+fBaseAddress, kindStr); 
+                               delta = 0;
+                               shift = 0;
+                       }
+                       else {
+                               more = false;
+                       }
+               }
+       } while (more);
+       return p;
+}
+
+template <typename A>
+void DyldInfoPrinter<A>::printSharedRegionInfo()
+{
+       if ( (fSharedRegionInfo == NULL) || (fSharedRegionInfo->datasize() == 0) ) {
+               printf("no shared region info\n");
+       }
+       else {
+               const uint8_t* infoStart = (uint8_t*)fHeader + fSharedRegionInfo->dataoff();
+               const uint8_t* infoEnd = &infoStart[fSharedRegionInfo->datasize()];
+               for(const uint8_t* p = infoStart; (*p != 0) && (p < infoEnd);) {
+                       uint8_t kind = *p++;
+                       p = this->printSharedRegionInfoForEachULEB128Address(p, kind);
+               }
+
+       }
+}
+
+template <>
+void DyldInfoPrinter<arm>::printFunctionStartLine(uint64_t addr)
+{
+       if ( addr & 1 )
+               printf("0x%0llX [thumb] %s\n", (addr & -2), symbolNameForAddress(addr & -2)); 
+       else
+               printf("0x%0llX         %s\n", addr, symbolNameForAddress(addr)); 
+}
+
+template <typename A>
+void DyldInfoPrinter<A>::printFunctionStartLine(uint64_t addr)
+{
+       printf("0x%0llX   %s\n", addr, symbolNameForAddress(addr)); 
+}
+
+
+template <typename A>
+void DyldInfoPrinter<A>::printFunctionStartsInfo()
+{
+       if ( (fFunctionStartsInfo == NULL) || (fFunctionStartsInfo->datasize() == 0) ) {
+               printf("no function starts info\n");
+       }
+       else {
+               const uint8_t* infoStart = (uint8_t*)fHeader + fFunctionStartsInfo->dataoff();
+               const uint8_t* infoEnd = &infoStart[fFunctionStartsInfo->datasize()];
+               uint64_t address = fBaseAddress;
+               for(const uint8_t* p = infoStart; (*p != 0) && (p < infoEnd); ) {
+                       uint64_t delta = 0;
+                       uint32_t shift = 0;
+                       bool more = true;
+                       do {
+                               uint8_t byte = *p++;
+                               delta |= ((byte & 0x7F) << shift);
+                               shift += 7;
+                               if ( byte < 0x80 ) {
+                                       address += delta;
+                                       printFunctionStartLine(address);
+                                       more = false;
+                               }
+                       } while (more);
+               }
+       }
+}
+
+template <typename A>
+void DyldInfoPrinter<A>::printDylibsInfo()
+{
+       printf("attributes     dependent dylibs\n");
+       for(typename std::vector<const macho_dylib_command<P>*>::iterator it = fDylibLoadCommands.begin(); it != fDylibLoadCommands.end(); ++it) {
+               const macho_dylib_command<P>* dylib  = *it;
+               const char* attribute = "";
+               switch ( dylib->cmd() ) {
+                       case LC_LOAD_WEAK_DYLIB:
+                               attribute = "weak_import";
+                               break;
+                       case LC_REEXPORT_DYLIB:
+                               attribute = "re-export";
+                               break;
+                       case LC_LOAD_UPWARD_DYLIB:
+                               attribute = "upward";
+                               break;
+                       case LC_LAZY_LOAD_DYLIB:
+                               attribute = "lazy_load";
+                               break;
+                       case LC_LOAD_DYLIB:
+                       default:
+                               break;
+               }
+               printf(" %-12s   %s\n", attribute, dylib->name());
+       }
+}
+
 
 template <>
 ppc::P::uint_t DyldInfoPrinter<ppc>::relocBase()
@@ -1465,6 +1720,27 @@ void DyldInfoPrinter<A>::printSymbolTableExportInfo()
        }
 }
 
+template <typename A>
+const char* DyldInfoPrinter<A>::symbolNameForAddress(uint64_t addr)
+{
+       // find exact match in globals
+       const macho_nlist<P>* lastExport = &fSymbols[fDynamicSymbolTable->iextdefsym()+fDynamicSymbolTable->nextdefsym()];
+       for (const macho_nlist<P>* sym = &fSymbols[fDynamicSymbolTable->iextdefsym()]; sym < lastExport; ++sym) {
+               if ( (sym->n_value() == addr) && ((sym->n_type() & N_TYPE) == N_SECT) && ((sym->n_type() & N_STAB) == 0) ) {
+                       return &fStrings[sym->n_strx()];
+               }
+       }
+       // find exact match in local symbols
+       const macho_nlist<P>* lastLocal = &fSymbols[fDynamicSymbolTable->ilocalsym()+fDynamicSymbolTable->nlocalsym()];
+       for (const macho_nlist<P>* sym = &fSymbols[fDynamicSymbolTable->ilocalsym()]; sym < lastLocal; ++sym) {
+               if ( (sym->n_value() == addr) && ((sym->n_type() & N_TYPE) == N_SECT) && ((sym->n_type() & N_STAB) == 0) ) {
+                       return &fStrings[sym->n_strx()];
+               }
+       }
+
+
+       return "?";
+}
  
 template <typename A>
 void DyldInfoPrinter<A>::printClassicBindingInfo()
@@ -1679,12 +1955,14 @@ static void dump(const char* path)
 static void usage()
 {
        fprintf(stderr, "Usage: dyldinfo [-arch <arch>] <options> <mach-o file>\n"
+                       "\t-dylibs           print dependent dylibs\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"
                        "\t-lazy_bind        print addresses dyld will lazily set on first use\n"
                        "\t-export           print addresses of all symbols this file exports\n"
                        "\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"
                );
 }
@@ -1754,6 +2032,18 @@ int main(int argc, const char* argv[])
                                else if ( strcmp(arg, "-export_dot") == 0 ) {
                                        printExportGraph = true;
                                }
+                               else if ( strcmp(arg, "-export_trie_nodes") == 0 ) {
+                                       printExportNodes = true;
+                               }
+                               else if ( strcmp(arg, "-shared_region") == 0 ) {
+                                       printSharedRegion = true;
+                               }
+                               else if ( strcmp(arg, "-function_starts") == 0 ) {
+                                       printFunctionStarts = true;
+                               }
+                               else if ( strcmp(arg, "-dylibs") == 0 ) {
+                                       printDylibs = true;
+                               }
                                else {
                                        throwf("unknown option: %s\n", arg);
                                }
index 68fdbb802009cf8319818e1cffdf4e380b79ff60..295fa19798fa38eab3cbae9e3f56398fc88185f9 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
  *
- * Copyright (c) 2006-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2006-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -52,6 +52,26 @@ void throwf(const char* format, ...)
        throw t;
 }
 
+static uint64_t read_uleb128(const uint8_t*& p, const uint8_t* end)
+{
+       uint64_t result = 0;
+       int              bit = 0;
+       do {
+               if (p == end)
+                       throwf("malformed uleb128");
+
+               uint64_t slice = *p & 0x7f;
+
+               if (bit >= 64 || slice << bit >> bit != slice)
+                       throwf("uleb128 too big");
+               else {
+                       result |= (slice << bit);
+                       bit += 7;
+               }
+       } 
+       while (*p++ & 0x80);
+       return result;
+}
 
 template <typename A>
 class MachOChecker
@@ -88,6 +108,8 @@ private:
        void                                                                            checkLocalReloation(const macho_relocation_info<P>* reloc);
        pint_t                                                                          relocBase();
        bool                                                                            addressInWritableSegment(pint_t address);
+       bool                                                                            hasTextRelocInRange(pint_t start, pint_t end);
+       pint_t                                                                          segStartAddress(uint8_t segIndex);
 
        const char*                                                                     fPath;
        const macho_header<P>*                                          fHeader;
@@ -106,7 +128,9 @@ private:
        bool                                                                            fWriteableSegmentWithAddrOver4G;
        const macho_segment_command<P>*                         fFirstSegment;
        const macho_segment_command<P>*                         fFirstWritableSegment;
+       const macho_dyld_info_command<P>*                       fDyldInfo;
        uint32_t                                                                        fSectionCount;
+       std::vector<const macho_segment_command<P>*>fSegments;
 };
 
 
@@ -211,7 +235,7 @@ template <typename A>
 MachOChecker<A>::MachOChecker(const uint8_t* fileContent, uint32_t fileLength, const char* path)
  : fHeader(NULL), fLength(fileLength), fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fDynamicSymbolTable(NULL), fIndirectTableCount(0),
  fLocalRelocations(NULL),  fLocalRelocationsCount(0),  fExternalRelocations(NULL),  fExternalRelocationsCount(0),
- fWriteableSegmentWithAddrOver4G(false), fFirstSegment(NULL), fFirstWritableSegment(NULL), fSectionCount(0)
+ fWriteableSegmentWithAddrOver4G(false), fFirstSegment(NULL), fFirstWritableSegment(NULL), fDyldInfo(NULL), fSectionCount(0)
 {
        // sanity check
        if ( ! validFile(fileContent) )
@@ -241,7 +265,7 @@ void MachOChecker<A>::checkMachHeader()
                throw "sizeofcmds in mach_header is larger than file";
        
        uint32_t flags = fHeader->flags();
-       const uint32_t invalidBits = MH_INCRLINK | MH_LAZY_INIT | 0xFFC00000;
+       const uint32_t invalidBits = MH_INCRLINK | MH_LAZY_INIT | 0xFE000000;
        if ( flags & invalidBits )
                throw "invalid bits in mach_header flags";
        if ( (flags & MH_NO_REEXPORTED_DYLIBS) && (fHeader->filetype() != MH_DYLIB) ) 
@@ -287,8 +311,14 @@ void MachOChecker<A>::checkLoadCommands()
                        case LC_REEXPORT_DYLIB:
                        case LC_SEGMENT_SPLIT_INFO:
                        case LC_CODE_SIGNATURE:
+                       case LC_LOAD_UPWARD_DYLIB:
+                       case LC_VERSION_MIN_MACOSX:
+                       case LC_VERSION_MIN_IPHONEOS:
+                       case LC_FUNCTION_STARTS:
+                               break;
                        case LC_DYLD_INFO:
                        case LC_DYLD_INFO_ONLY:
+                               fDyldInfo = (macho_dyld_info_command<P>*)cmd;
                                break;
                        case LC_ENCRYPTION_INFO:
                                encryption_info = (macho_encryption_info_command<P>*)cmd;
@@ -312,6 +342,7 @@ void MachOChecker<A>::checkLoadCommands()
        for (uint32_t i = 0; i < cmd_count; ++i) {
                if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
                        const macho_segment_command<P>* segCmd = (const macho_segment_command<P>*)cmd;
+                       fSegments.push_back(segCmd);
                        if ( segCmd->cmdsize() != (sizeof(macho_segment_command<P>) + segCmd->nsects() * sizeof(macho_section_content<P>)) )
                                throw "invalid segment load command size";
                                
@@ -381,7 +412,9 @@ void MachOChecker<A>::checkLoadCommands()
                                        throwf("section %s vm address not within segment", sect->sectname());
                                if ( (sect->addr()+sect->size()) > endAddr )
                                        throwf("section %s vm address not within segment", sect->sectname());
-                               if ( ((sect->flags() & SECTION_TYPE) != S_ZEROFILL) && (segCmd->filesize() != 0) ) {
+                               if ( ((sect->flags() & SECTION_TYPE) != S_ZEROFILL) 
+                                       && ((sect->flags() & SECTION_TYPE) != S_THREAD_LOCAL_ZEROFILL) 
+                                       && (segCmd->filesize() != 0) ) {
                                        if ( sect->offset() < startOffset )
                                                throwf("section %s file offset not within segment", sect->sectname());
                                        if ( (sect->offset()+sect->size()) > endOffset )
@@ -470,7 +503,7 @@ void MachOChecker<A>::checkLoadCommands()
                                        if ( isStaticExecutable )
                                                throw "LC_DYSYMTAB should not be used in static executable";
                                        foundDynamicSymTab = true;
-                                       fDynamicSymbolTable = (struct macho_dysymtab_command<P>*)cmd;
+                                       fDynamicSymbolTable = (macho_dysymtab_command<P>*)cmd;
                                        fIndirectTable = (uint32_t*)((char*)fHeader + fDynamicSymbolTable->indirectsymoff());
                                        fIndirectTableCount = fDynamicSymbolTable->nindirectsyms();
                                        if ( fIndirectTableCount != 0  ) {
@@ -507,7 +540,7 @@ void MachOChecker<A>::checkLoadCommands()
                                {
                                        if ( isStaticExecutable )
                                                throw "LC_SEGMENT_SPLIT_INFO should not be used in static executable";
-                                       const macho_linkedit_data_command<P>* info = (struct macho_linkedit_data_command<P>*)cmd;
+                                       const macho_linkedit_data_command<P>* info = (macho_linkedit_data_command<P>*)cmd;
                                        if ( info->dataoff() < linkEditSegment->fileoff() )
                                                throw "split seg info not in __LINKEDIT";
                                        if ( (info->dataoff()+info->datasize()) > (linkEditSegment->fileoff()+linkEditSegment->filesize()) )
@@ -518,6 +551,19 @@ void MachOChecker<A>::checkLoadCommands()
                                                throw "split seg info size not a multiple of pointer size";
                                }
                                break;
+                       case LC_FUNCTION_STARTS:
+                               {
+                                       const macho_linkedit_data_command<P>* info = (macho_linkedit_data_command<P>*)cmd;
+                                       if ( info->dataoff() < linkEditSegment->fileoff() )
+                                               throw "function starts data not in __LINKEDIT";
+                                       if ( (info->dataoff()+info->datasize()) > (linkEditSegment->fileoff()+linkEditSegment->filesize()) )
+                                               throw "function starts data not in __LINKEDIT";
+                                       if ( (info->dataoff() % sizeof(pint_t)) != 0 )
+                                               throw "function starts data table not pointer aligned";
+                                       if ( (info->datasize() % sizeof(pint_t)) != 0 )
+                                               throw "function starts data size not a multiple of pointer size";
+                               }
+                               break;
                }
                cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
        }
@@ -543,6 +589,9 @@ void MachOChecker<A>::checkSection(const macho_segment_command<P>* segCmd, const
 template <typename A>
 void MachOChecker<A>::checkIndirectSymbolTable()
 {
+       // static executables don't have indirect symbol table
+       if ( fDynamicSymbolTable == NULL )
+               return;
        const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
        const uint32_t cmd_count = fHeader->ncmds();
        const macho_load_command<P>* cmd = cmds;
@@ -596,7 +645,11 @@ void MachOChecker<A>::checkSymbolTable()
                        //fprintf(stderr, "sym[%d] = %s\n", i, symName);
                        if ( externalNames.find(symName) != externalNames.end() )
                                throwf("duplicate external symbol: %s", symName);
-                       externalNames.insert(symName);
+                       if ( (p->n_type() & N_EXT) == 0 )
+                               throwf("non-external symbol in external symbol range: %s", symName);
+                       // don't add N_INDR to externalNames because there is likely an undefine with same name
+                       if ( (p->n_type() & N_INDR) == 0 )
+                               externalNames.insert(symName);
                }
                // verify no undefines with same name as an external symbol
                const macho_nlist<P>* const     undefinesStart = &fSymbols[fDynamicSymbolTable->iundefsym()];
@@ -876,8 +929,128 @@ void MachOChecker<A>::checkRelocations()
        for (const macho_relocation_info<P>* reloc = fLocalRelocations; reloc < localRelocsEnd; ++reloc) {
                this->checkLocalReloation(reloc);
        }
+       
+       // verify any section with S_ATTR_LOC_RELOC bits set actually has text relocs
+       const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
+       const uint32_t cmd_count = fHeader->ncmds();
+       const macho_load_command<P>* cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
+                       const macho_segment_command<P>* segCmd = (const macho_segment_command<P>*)cmd;
+                       // if segment is writable, we are fine
+                       if ( (segCmd->initprot() & VM_PROT_WRITE) != 0 ) 
+                               continue;
+                       // look at sections that have text reloc bit set
+                       const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
+                       const macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
+                       for(const macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
+                               if ( (sect->flags() & S_ATTR_LOC_RELOC) != 0 ) {
+                                       if ( ! hasTextRelocInRange(sect->addr(), sect->addr()+sect->size()) ) {
+                                               throwf("section %s has attribute set that it has relocs, but it has none", sect->sectname());
+                                       }
+                               }
+                       }
+               }
+               cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+       }
 }
 
+template <typename A>
+typename A::P::uint_t MachOChecker<A>::segStartAddress(uint8_t segIndex)
+{
+       if ( segIndex > fSegments.size() )
+               throw "segment index out of range";
+       return fSegments[segIndex]->vmaddr();
+}
+
+template <typename A>
+bool MachOChecker<A>::hasTextRelocInRange(pint_t rangeStart, pint_t rangeEnd)
+{
+       // look at local relocs
+       const macho_relocation_info<P>* const localRelocsEnd = &fLocalRelocations[fLocalRelocationsCount];
+       for (const macho_relocation_info<P>* reloc = fLocalRelocations; reloc < localRelocsEnd; ++reloc) {
+               pint_t relocAddress = reloc->r_address() + this->relocBase();
+               if ( (rangeStart <= relocAddress) && (relocAddress < rangeEnd) )
+                       return true;
+       }       
+       // look rebase info
+       if ( fDyldInfo != NULL ) {
+               const uint8_t* p = (uint8_t*)fHeader + fDyldInfo->rebase_off();
+               const uint8_t* end = &p[fDyldInfo->rebase_size()];
+               
+               uint8_t type = 0;
+               uint64_t segOffset = 0;
+               uint32_t count;
+               uint32_t skip;
+               int segIndex;
+               pint_t segStartAddr = 0;
+               pint_t addr;
+               bool done = false;
+               while ( !done && (p < end) ) {
+                       uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
+                       uint8_t opcode = *p & REBASE_OPCODE_MASK;
+                       ++p;
+                       switch (opcode) {
+                               case REBASE_OPCODE_DONE:
+                                       done = true;
+                                       break;
+                               case REBASE_OPCODE_SET_TYPE_IMM:
+                                       type = immediate;
+                                       break;
+                               case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+                                       segIndex = immediate;
+                                       segStartAddr = segStartAddress(segIndex);
+                                       segOffset = read_uleb128(p, end);
+                                       break;
+                               case REBASE_OPCODE_ADD_ADDR_ULEB:
+                                       segOffset += read_uleb128(p, end);
+                                       break;
+                               case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
+                                       segOffset += immediate*sizeof(pint_t);
+                                       break;
+                               case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
+                                       for (int i=0; i < immediate; ++i) {
+                                               addr = segStartAddr+segOffset;
+                                               if ( (rangeStart <= addr) && (addr < rangeEnd) )
+                                                       return true;
+                                               //printf("%-7s %-16s 0x%08llX  %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
+                                               segOffset += sizeof(pint_t);
+                                       }
+                                       break;
+                               case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
+                                       count = read_uleb128(p, end);
+                                       for (uint32_t i=0; i < count; ++i) {
+                                               addr = segStartAddr+segOffset;
+                                               if ( (rangeStart <= addr) && (addr < rangeEnd) )
+                                                       return true;
+                                               //printf("%-7s %-16s 0x%08llX  %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
+                                               segOffset += sizeof(pint_t);
+                                       }
+                                       break;
+                               case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
+                                       addr = segStartAddr+segOffset;
+                                       if ( (rangeStart <= addr) && (addr < rangeEnd) )
+                                               return true;
+                                       //printf("%-7s %-16s 0x%08llX  %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
+                                       segOffset += read_uleb128(p, end) + sizeof(pint_t);
+                                       break;
+                               case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
+                                       count = read_uleb128(p, end);
+                                       skip = read_uleb128(p, end);
+                                       for (uint32_t i=0; i < count; ++i) {
+                                               addr = segStartAddr+segOffset;
+                                               if ( (rangeStart <= addr) && (addr < rangeEnd) )
+                                                       return true;
+                                               //printf("%-7s %-16s 0x%08llX  %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
+                                               segOffset += skip + sizeof(pint_t);
+                                       }
+                                       break;
+                               default:
+                                       throwf("bad rebase opcode %d", *p);
+                       }
+               }       
+       }
+}
 
 static void check(const char* path)
 {
index f8dc1ee1f34caf6600ca0aece7233f716ea59e51..c04fb0a941e29b1fe22992f299563109efff0582 100644 (file)
@@ -302,7 +302,6 @@ void Rebaser<A>::setBaseAddress(uint64_t addr)
 template <typename A>
 void Rebaser<A>::adjustLoadCommands()
 {
-       const macho_segment_command<P>* highestSegmentCmd = NULL; 
        const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
        const uint32_t cmd_count = fHeader->ncmds();
        const macho_load_command<P>* cmd = cmds;
@@ -317,6 +316,8 @@ void Rebaser<A>::adjustLoadCommands()
                                break;
                        case LC_LOAD_DYLIB:
                        case LC_LOAD_WEAK_DYLIB:
+                       case LC_REEXPORT_DYLIB:
+                       case LC_LOAD_UPWARD_DYLIB:
                                if ( (fHeader->flags() & MH_PREBOUND) != 0 ) {
                                        // clear expected timestamps so that this image will load with invalid prebinding 
                                        macho_dylib_command<P>* dylib  = (macho_dylib_command<P>*)cmd;
@@ -326,7 +327,7 @@ void Rebaser<A>::adjustLoadCommands()
                        case macho_routines_command<P>::CMD:
                                // update -init command
                                {
-                                       struct macho_routines_command<P>* routines = (struct macho_routines_command<P>*)cmd;
+                                       macho_routines_command<P>* routines = (macho_routines_command<P>*)cmd;
                                        routines->set_init_address(routines->init_address() + fSlide);
                                }
                                break;
@@ -374,6 +375,7 @@ void Rebaser<A>::adjustSymbolTable()
 {
        const macho_dysymtab_command<P>* dysymtab = NULL;
        macho_nlist<P>* symbolTable = NULL;
+       const char* strings = NULL;
 
        // get symbol table info
        const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
@@ -385,7 +387,8 @@ void Rebaser<A>::adjustSymbolTable()
                                {
                                        const macho_symtab_command<P>* symtab = (macho_symtab_command<P>*)cmd;
                                        symbolTable = (macho_nlist<P>*)(((uint8_t*)fHeader) + symtab->symoff());
-                               }
+                                       strings = (char*)(((uint8_t*)fHeader) + symtab->stroff());
+                }    
                                break;
                        case LC_DYSYMTAB:
                                dysymtab = (macho_dysymtab_command<P>*)cmd;
@@ -404,8 +407,23 @@ void Rebaser<A>::adjustSymbolTable()
        // walk all local symbols and slide their n_value
        macho_nlist<P>* lastLocal = &symbolTable[dysymtab->ilocalsym()+dysymtab->nlocalsym()];
        for (macho_nlist<P>* entry = &symbolTable[dysymtab->ilocalsym()]; entry < lastLocal; ++entry) {
-               if ( entry->n_sect() != NO_SECT )
+               if ( ((entry->n_type() & N_STAB) == 0) && ((entry->n_type() & N_TYPE) == N_SECT) ) {
                        entry->set_n_value(entry->n_value() + fSlide);
+               }
+               else if ( entry->n_type() & N_STAB ) {
+                       // some stabs need to be slid too
+                       switch ( entry->n_type() ) {
+                               case N_FUN:
+                                       // don't slide end-of-function FUN which is FUN with no string
+                                       if ( (entry->n_strx() == 0) || (strings[entry->n_strx()] == '\0') )
+                                               break;
+                               case N_BNSYM:
+                               case N_STSYM:
+                               case N_LCSYM:
+                                       entry->set_n_value(entry->n_value() + fSlide);
+                                       break;
+                       }
+               }
        }
        
        // FIXME Â¥Â¥Â¥ adjust dylib_module if it exists
@@ -448,7 +466,7 @@ void Rebaser<A>::rebaseAt(int segIndex, uint64_t offset, uint8_t type)
                                if ( segIndex == segCount ) {
                                        const macho_segment_command<P>* seg = (macho_segment_command<P>*)cmd;
                                        lastSegMappedStart = (uint8_t*)fHeader + seg->fileoff();
-                                       lastSegIndex == segCount;
+                                       lastSegIndex = segCount;
                                        break;
                                }
                                ++segCount;
index 098d93270ee0e43ff8978bf7926c09b80bb43088..81e677d2939d56186040e70b509c76f615092956 100644 (file)
@@ -59,8 +59,10 @@ class UnwindPrinter
 {
 public:
        static bool                                                                     validFile(const uint8_t* fileContent);
-       static UnwindPrinter<A>*                                                make(const uint8_t* fileContent, uint32_t fileLength, const char* path) 
-                                                                                                               { return new UnwindPrinter<A>(fileContent, fileLength, path); }
+       static UnwindPrinter<A>*                                                make(const uint8_t* fileContent, uint32_t fileLength, 
+                                                                                                                       const char* path, bool showFunctionNames) 
+                                                                                                               { return new UnwindPrinter<A>(fileContent, fileLength, 
+                                                                                                                                                                               path, showFunctionNames); }
        virtual                                                                         ~UnwindPrinter() {}
 
 
@@ -77,9 +79,10 @@ private:
 
        typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals>  StringSet;
 
-                                                                                               UnwindPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path);
+                                                                                               UnwindPrinter(const uint8_t* fileContent, uint32_t fileLength, 
+                                                                                                                               const char* path, bool showFunctionNames);
        bool                                                                            findUnwindSection();
-       void                                                                            printUnwindSection();
+       void                                                                            printUnwindSection(bool showFunctionNames);
        void                                                                            getSymbolTableInfo();
        const char*                                                                     functionName(pint_t addr);
        static const char*                                                      archName();
@@ -195,7 +198,7 @@ bool UnwindPrinter<arm>::validFile(const uint8_t* fileContent)
 
 
 template <typename A>
-UnwindPrinter<A>::UnwindPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path)
+UnwindPrinter<A>::UnwindPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path, bool showFunctionNames)
  : fHeader(NULL), fLength(fileLength), fUnwindSection(NULL),
    fStrings(NULL), fStringsEnd(NULL), fSymbols(NULL), fSymbolCount(0), fMachHeaderAddress(0)
 {
@@ -209,7 +212,7 @@ UnwindPrinter<A>::UnwindPrinter(const uint8_t* fileContent, uint32_t fileLength,
        getSymbolTableInfo();
        
        if ( findUnwindSection() )
-               printUnwindSection();
+               printUnwindSection(showFunctionNames);
 }
 
 
@@ -664,7 +667,7 @@ void UnwindPrinter<A>::decode(uint32_t encoding, const uint8_t* funcStart, char*
 }
 
 template <typename A>
-void UnwindPrinter<A>::printUnwindSection()
+void UnwindPrinter<A>::printUnwindSection(bool showFunctionNames)
 {
        const uint8_t* sectionContent = (uint8_t*)fHeader + fUnwindSection->offset();
        macho_unwind_info_section_header<P>* sectionHeader = (macho_unwind_info_section_header<P>*)(sectionContent);
@@ -700,8 +703,8 @@ void UnwindPrinter<A>::printUnwindSection()
        printf("\tLSDA table: (section offset 0x%08X, count=%u)\n", lsdaIndexArraySectionOffset, lsdaIndexArrayCount);
        macho_unwind_info_section_header_lsda_index_entry<P>* lindex = (macho_unwind_info_section_header_lsda_index_entry<P>*)&sectionContent[lsdaIndexArraySectionOffset];
        for (uint32_t i=0; i < lsdaIndexArrayCount; ++i) {
-               printf("\t\t[%3u] funcOffset=0x%08X, lsdaOffset=0x%08X,  %s\n", 
-                                       i, lindex[i].functionOffset(), lindex[i].lsdaOffset(), functionName(lindex[i].functionOffset()+fMachHeaderAddress));
+               const char* name = showFunctionNames ? functionName(lindex[i].functionOffset()+fMachHeaderAddress) : "";
+               printf("\t\t[%3u] funcOffset=0x%08X, lsdaOffset=0x%08X,  %s\n", i, lindex[i].functionOffset(), lindex[i].lsdaOffset(), name);
                if ( *(((uint8_t*)fHeader) + lindex[i].lsdaOffset()) != 0xFF )
                        fprintf(stderr, "BAD LSDA entry (does not start with 0xFF) for %s\n", functionName(lindex[i].functionOffset()+fMachHeaderAddress));
        }
@@ -731,8 +734,9 @@ void UnwindPrinter<A>::printUnwindSection()
                                } 
                                char encodingString[100];
                                decode(entry[j].encoding(), ((const uint8_t*)fHeader)+funcOffset, encodingString);
+                               const char* name = showFunctionNames ? functionName(funcOffset+fMachHeaderAddress) : "";
                                printf("\t\t\t[%3u] funcOffset=0x%08X, encoding=0x%08X (%-40s) %s\n", 
-                                       j, funcOffset, entry[j].encoding(), encodingString, functionName(funcOffset+fMachHeaderAddress));
+                                       j, funcOffset, entry[j].encoding(), encodingString, name);
                        }
                }
                else if ( page->kind() == UNWIND_SECOND_LEVEL_COMPRESSED ) {
@@ -755,7 +759,7 @@ void UnwindPrinter<A>::printUnwindSection()
                                char encodingString[100];
                                uint32_t funcOff = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entries[j])+baseFunctionOffset;
                                decode(encoding, ((const uint8_t*)fHeader)+funcOff, encodingString);
-                               const char* name = functionName(funcOff+fMachHeaderAddress);
+                               const char* name = showFunctionNames ? functionName(funcOff+fMachHeaderAddress) : "";
                                if ( encoding & UNWIND_HAS_LSDA ) {
                                        // verify there is a corresponding entry in lsda table
                                        bool found = false;
@@ -780,7 +784,7 @@ void UnwindPrinter<A>::printUnwindSection()
 
 }
 
-static void dump(const char* path, const std::set<cpu_type_t>& onlyArchs)
+static void dump(const char* path, const std::set<cpu_type_t>& onlyArchs, bool showFunctionNames)
 {
        struct stat stat_buf;
        
@@ -807,31 +811,31 @@ static void dump(const char* path, const std::set<cpu_type_t>& onlyArchs)
                                        switch(cputype) {
                                        case CPU_TYPE_POWERPC:
                                                if ( UnwindPrinter<ppc>::validFile(p + offset) )
-                                                       UnwindPrinter<ppc>::make(p + offset, size, path);
+                                                       UnwindPrinter<ppc>::make(p + offset, size, path, showFunctionNames);
                                                else
                                                        throw "in universal file, ppc slice does not contain ppc mach-o";
                                                break;
                                        case CPU_TYPE_I386:
                                                if ( UnwindPrinter<x86>::validFile(p + offset) )
-                                                       UnwindPrinter<x86>::make(p + offset, size, path);
+                                                       UnwindPrinter<x86>::make(p + offset, size, path, showFunctionNames);
                                                else
                                                        throw "in universal file, i386 slice does not contain i386 mach-o";
                                                break;
                                        case CPU_TYPE_POWERPC64:
                                                if ( UnwindPrinter<ppc64>::validFile(p + offset) )
-                                                       UnwindPrinter<ppc64>::make(p + offset, size, path);
+                                                       UnwindPrinter<ppc64>::make(p + offset, size, path, showFunctionNames);
                                                else
                                                        throw "in universal file, ppc64 slice does not contain ppc64 mach-o";
                                                break;
                                        case CPU_TYPE_X86_64:
                                                if ( UnwindPrinter<x86_64>::validFile(p + offset) )
-                                                       UnwindPrinter<x86_64>::make(p + offset, size, path);
+                                                       UnwindPrinter<x86_64>::make(p + offset, size, path, showFunctionNames);
                                                else
                                                        throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
                                                break;
                                        case CPU_TYPE_ARM:
                                                if ( UnwindPrinter<arm>::validFile(p + offset) )
-                                                       UnwindPrinter<arm>::make(p + offset, size, path);
+                                                       UnwindPrinter<arm>::make(p + offset, size, path, showFunctionNames);
                                                else
                                                        throw "in universal file, arm slice does not contain arm mach-o";
                                                break;
@@ -842,19 +846,19 @@ static void dump(const char* path, const std::set<cpu_type_t>& onlyArchs)
                        }
                }
                else if ( UnwindPrinter<x86>::validFile(p) && onlyArchs.count(CPU_TYPE_I386) ) {
-                       UnwindPrinter<x86>::make(p, length, path);
+                       UnwindPrinter<x86>::make(p, length, path, showFunctionNames);
                }
                else if ( UnwindPrinter<ppc>::validFile(p) && onlyArchs.count(CPU_TYPE_POWERPC) ) {
-                       UnwindPrinter<ppc>::make(p, length, path);
+                       UnwindPrinter<ppc>::make(p, length, path, showFunctionNames);
                }
                else if ( UnwindPrinter<ppc64>::validFile(p) && onlyArchs.count(CPU_TYPE_POWERPC64) ) {
-                       UnwindPrinter<ppc64>::make(p, length, path);
+                       UnwindPrinter<ppc64>::make(p, length, path, showFunctionNames);
                }
                else if ( UnwindPrinter<x86_64>::validFile(p) && onlyArchs.count(CPU_TYPE_X86_64) ) {
-                       UnwindPrinter<x86_64>::make(p, length, path);
+                       UnwindPrinter<x86_64>::make(p, length, path, showFunctionNames);
                }
                else if ( UnwindPrinter<arm>::validFile(p) && onlyArchs.count(CPU_TYPE_ARM) ) {
-                       UnwindPrinter<arm>::make(p, length, path);
+                       UnwindPrinter<arm>::make(p, length, path, showFunctionNames);
                }
                else {
                        throw "not a known file type";
@@ -870,6 +874,7 @@ int main(int argc, const char* argv[])
 {
        std::set<cpu_type_t> onlyArchs;
        std::vector<const char*> files;
+       bool showFunctionNames = true;
        
        try {
                for(int i=1; i < argc; ++i) {
@@ -890,6 +895,9 @@ int main(int argc, const char* argv[])
                                        else 
                                                throwf("unknown architecture %s", arch);
                                }
+                               else if ( strcmp(arg, "-no_symbols") == 0 ) {
+                                       showFunctionNames = false;
+                               }
                                else {
                                        throwf("unknown option: %s\n", arg);
                                }
@@ -910,7 +918,7 @@ int main(int argc, const char* argv[])
                
                // process each file
                for(std::vector<const char*>::iterator it=files.begin(); it != files.end(); ++it) {
-                       dump(*it, onlyArchs);
+                       dump(*it, onlyArchs, showFunctionNames);
                }
                
        }
index 8168e794f181fabaaf4038b9dbd7085c778dc4c8..9c92392d975d994a903e10197782fa1d18bcf0e0 100755 (executable)
@@ -93,6 +93,15 @@ sub process_entry
     {
        printf "%-40s FAIL Makefile failure\n", $test_name;
        $total_count++;
+       #my $line1;
+       #foreach $line1 (@{$$tbl{stdout}})
+       #{
+       #    printf "stdout: %s\n", $line1;
+       #}
+       #foreach $line1 (@{$$tbl{stderr}})
+       #{
+       #    printf "stderr: %s\n", $line1;
+       #}
        return;
     }
 
@@ -127,5 +136,14 @@ sub process_entry
     {
        printf "%-40s AMBIGIOUS missing [X]PASS/[X]FAIL\n", $test_name;
        $total_count++;
+       #my $line1;
+       #foreach $line1 (@{$$tbl{stdout}})
+       #{
+       #    printf "stdout: %s\n", $line1;
+       #}
+       #foreach $line1 (@{$$tbl{stderr}})
+       #{
+       #    printf "stderr: %s\n", $line1;
+       #}
     }
 }
index 7222efa3774d64124f0b575c4b93374231f85a38..642e4917d5c765537ed9b8a3d979c608199d5289 100644 (file)
@@ -6,7 +6,7 @@ SHELL = /bin/sh
 ARCH ?= $(shell arch)
 
 # set default to be all
-VALID_ARCHS ?= "ppc ppc64 i386 x86_64 armv6"
+VALID_ARCHS ?= "i386 x86_64 armv6"
 
 MYDIR=$(shell cd ../../bin;pwd)
 LD                     = ld
@@ -14,6 +14,7 @@ OBJECTDUMP    = ObjectDump
 MACHOCHECK     = machocheck
 OTOOL          = otool
 REBASE         = rebase
+DYLDINFO       = dyldinfo
 
 ifdef BUILT_PRODUCTS_DIR
        # if run within Xcode, add the just built tools to the command path
@@ -23,17 +24,22 @@ ifdef BUILT_PRODUCTS_DIR
        OBJECTDUMP      = ${BUILT_PRODUCTS_DIR}/ObjectDump
        MACHOCHECK      = ${BUILT_PRODUCTS_DIR}/machocheck
        REBASE          = ${BUILT_PRODUCTS_DIR}/rebase
+       UNWINDDUMP  = ${BUILT_PRODUCTS_DIR}/unwinddump
+       DYLDINFO        = ${BUILT_PRODUCTS_DIR}/dyldinfo
 else
        ifneq "$(findstring /unit-tests/test-cases/, $(shell pwd))" ""
                # if run from Terminal inside unit-test directory
                RELEASEDIR=$(shell cd ../../../build/Release;pwd)
+               RELEASEADIR=$(shell cd ../../../build/Release-assert;pwd)
                DEBUGDIR=$(shell cd ../../../build/Debug;pwd)
-               PATH := ${RELEASEDIR}:${DEBUGDIR}:${MYDIR}:${PATH}
-               COMPILER_PATH := ${RELEASEDIR}:${DEBUGDIR}:${MYDIR}:${COMPILER_PATH}
-               LD                      = ${RELEASEDIR}/ld
-               OBJECTDUMP      = ${RELEASEDIR}/ObjectDump
-               MACHOCHECK      = ${RELEASEDIR}/machocheck
-               REBASE          = ${RELEASEDIR}/rebase
+               PATH := ${RELEASEADIR}:${RELEASEDIR}:${DEBUGDIR}:${MYDIR}:${PATH}
+               COMPILER_PATH := ${RELEASEADIR}:${RELEASEDIR}:${DEBUGDIR}:${MYDIR}:${COMPILER_PATH}
+               LD                      = ${DEBUGDIR}/ld
+               OBJECTDUMP      = ${DEBUGDIR}/ObjectDump
+               MACHOCHECK      = ${DEBUGDIR}/machocheck
+               REBASE          = ${DEBUGDIR}/rebase
+               UNWINDDUMP  = ${DEBUGDIR}/unwinddump
+               DYLDINFO        = ${DEBUGDIR}/dyldinfo
        else
                PATH := ${MYDIR}:${PATH}:
                COMPILER_PATH := ${MYDIR}:${COMPILER_PATH}:
@@ -42,12 +48,15 @@ endif
 export PATH
 export COMPILER_PATH
 
+ifeq ($(ARCH),ppc)
+       SDKExtra = -isysroot /Developer/SDKs/MacOSX10.6.sdk
+endif
 
-CC              = gcc-4.2 -arch ${ARCH} ${SDKExtra}
+CC              = cc -arch ${ARCH} ${SDKExtra}
 CCFLAGS = -Wall -std=c99
 ASMFLAGS =
 
-CXX              = g++-4.2 -arch ${ARCH} ${SDKExtra}
+CXX              = c++ -arch ${ARCH} ${SDKExtra}
 CXXFLAGS = -Wall
 
 ifeq ($(ARCH),armv6)
@@ -89,6 +98,7 @@ else
   FILEARCH = $(ARCH)
 endif
 
+
 RM      = rm
 RMFLAGS = -rf
 
index 842ce77e079f159cdbf68b5bcf309e3229ac88a1..f6275a758569b5fabf33e1d7f6ceb13b52b3a4e1 100755 (executable)
@@ -6,6 +6,7 @@ unset LD_TRACE_DYLIBS
 unset LD_TRACE_ARCHIVES
 
 export DYLD_FALLBACK_LIBRARY_PATH=${DYLD_FALLBACK_LIBRARY_PATH}:/Developer/usr/lib
+export MACOSX_DEPLOYMENT_TARGET=10.7
 # cd into test-cases directory
 cd `echo "$0" | sed 's/run-all-unit-tests/test-cases/'`
 
index a3a256fac91617f1d0abb8b2a618001c848d3641..e178ddb02e110d092265a6bf6527bd76b6638dbf 100644 (file)
@@ -33,7 +33,7 @@ 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}
diff --git a/unit-tests/test-cases/Lpath/Makefile b/unit-tests/test-cases/Lpath/Makefile
new file mode 100644 (file)
index 0000000..b580706
--- /dev/null
@@ -0,0 +1,43 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is a sanity check that ld
+# can link a hello-world program with no errors (or crashes)
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} foo.c -c -o foo.o
+       mkdir -p hide
+       libtool foo.o -static -o hide/libfoo.a
+       ${CC} ${CCFLAGS} main.c -c -o main.o
+       ${LD} main.o -lfoo -Lhide -r -o mainfoo.o
+       ${LD} main.o -lfoo -L hide -r -o mainfoo.o
+       ${PASS_IFF} true
+
+clean:
+       rm -rf foo.o hide main.o mainfoo.o
diff --git a/unit-tests/test-cases/Lpath/foo.c b/unit-tests/test-cases/Lpath/foo.c
new file mode 100644 (file)
index 0000000..8c5841a
--- /dev/null
@@ -0,0 +1,2 @@
+
+int foo() { return 0; }
diff --git a/unit-tests/test-cases/Lpath/main.c b/unit-tests/test-cases/Lpath/main.c
new file mode 100644 (file)
index 0000000..49deebf
--- /dev/null
@@ -0,0 +1,8 @@
+
+extern int foo();
+
+int main()
+{
+       foo();
+       return 0;
+}
\ No newline at end of file
index 216867cef400effc73ec5565338aaf712f6b2cd5..1aee96f590010f85f15e834fe84bc5199be16f8c 100644 (file)
@@ -1,3 +1,7 @@
 
   .globl _myAbs
-  .set _myAbs, 0xfe000000
+#if __LP64__
+       _myAbs = 0x012345678
+#else
+       _myAbs = 0xfe000000
+#endif
index 9e8732971261d3cd3e334b491fc33defaf755c95..f700dbfad21d4180af9856a98e50f48ab72db7c2 100644 (file)
@@ -41,11 +41,11 @@ all:
        ${CC} ${ASMFLAGS} aliases.s -c -o aliases.tmp.${ARCH}.o
        ${FAIL_IF_BAD_OBJ} aliases.tmp.${ARCH}.o
 
-       ${LD} -arch ${ARCH} -r aliases.tmp.${ARCH}.o -alias _foo _fooalt -alias _foo _fooalt2 -o aliases.cmdline.${ARCH}.o
+       ${LD} -arch ${ARCH} -r -keep_private_externs aliases.tmp.${ARCH}.o -alias _foo _fooalt -alias _foo _fooalt2 -alias _hidden _glob -o aliases.cmdline.${ARCH}.o
        ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content -no_sort aliases.cmdline.${ARCH}.o > aliases.cmdline.${ARCH}.o.dump
        ${FAIL_IF_ERROR} diff aliases.source.${ARCH}.o.dump  aliases.cmdline.${ARCH}.o.dump
 
-       ${LD} -arch ${ARCH} -r aliases.tmp.${ARCH}.o -alias_list aliases.txt -o aliases.file.${ARCH}.o
+       ${LD} -arch ${ARCH} -r -keep_private_externs aliases.tmp.${ARCH}.o -alias_list aliases.txt -o aliases.file.${ARCH}.o
        ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content -no_sort aliases.file.${ARCH}.o > aliases.file.${ARCH}.o.dump
        ${PASS_IFF} diff aliases.source.${ARCH}.o.dump  aliases.file.${ARCH}.o.dump
        
index ffab4a9f285bc22f654ddcf0d6f64c5bd7f0db02..48e59610cab671dc577e9caf042e8f24f310876e 100644 (file)
@@ -29,13 +29,20 @@ _temp:      nop
                .globl _foo
 _foo:  nop
                nop
+               
+               .globl _hidden
+               .private_extern _hidden
+_hidden:       nop
+                       nop
 
 #if ALIASES
                .globl _fooalt
                .globl _fooalt2
+               .globl _glob
 /* this should make an alias "_fooalt" for "_foo" */
 _fooalt = _foo 
 _fooalt2 = _foo        
+_glob   = _hidden
 #endif
 
 _bar:  nop
index 291f2f7ef68ac43d02d48c57c954013563589f73..d0a3da932f2ee1fbe4984f7d10bc4fabb32c1d88 100644 (file)
@@ -2,5 +2,6 @@ _foo            _fooalt
 # comment
 _foo   _fooalt2
 
+_hidden        _glob
 
 
diff --git a/unit-tests/test-cases/allow_heap_execute/Makefile b/unit-tests/test-cases/allow_heap_execute/Makefile
new file mode 100644 (file)
index 0000000..57c3da7
--- /dev/null
@@ -0,0 +1,35 @@
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test the we set the data execute bit for i386
+#
+
+run: run-${ARCH}
+
+run-x86_64:
+       ${PASS_IFF} true
+       
+run-armv6: 
+       ${PASS_IFF} true
+
+run-armv7: 
+       ${PASS_IFF} true
+
+run-ppc:
+       ${PASS_IFF} true
+
+
+run-i386:
+       # Test with the flag
+       ${CC} ${CCFLAGS} main.c -o main-allow -Wl,-allow_heap_execute
+       ${FAIL_IF_BAD_MACHO} main-allow
+       ${OTOOL} -hv main-allow | grep MH_NO_HEAP_EXECUTION | ${FAIL_IF_STDIN}
+       # Test without the flag
+       ${CC} ${CCFLAGS} main.c -o main
+       ${OTOOL} -hv main | grep MH_NO_HEAP_EXECUTION | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+       rm -rf main main-allow
diff --git a/unit-tests/test-cases/allow_heap_execute/main.c b/unit-tests/test-cases/allow_heap_execute/main.c
new file mode 100644 (file)
index 0000000..e0d6d5d
--- /dev/null
@@ -0,0 +1,4 @@
+int main(void)
+{
+   return 0;
+}
diff --git a/unit-tests/test-cases/archive-ObjC-unexported/Makefile b/unit-tests/test-cases/archive-ObjC-unexported/Makefile
new file mode 100644 (file)
index 0000000..f94ee81
--- /dev/null
@@ -0,0 +1,44 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+#
+# The point of this test is to check that -ObjC loads all (and only)
+# .o files that contain Objective-C code.
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} foo.m -c -o foo.o 
+       ${CC} ${CCFLAGS} bar.m -c -o bar.o 
+       libtool -static bar.o foo.o -o libfoo.a
+       ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} main.m libfoo.a -o main -framework Foundation -dead_strip -Wl,-unexported_symbols_list,main.nexp 2>main.log
+       grep Foobar main.log | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_SUCCESS} true
+       
+clean:
+       rm -rf foo.o bar.o libfoo.a main.log
diff --git a/unit-tests/test-cases/archive-ObjC-unexported/bar.m b/unit-tests/test-cases/archive-ObjC-unexported/bar.m
new file mode 100644 (file)
index 0000000..ad598bc
--- /dev/null
@@ -0,0 +1,14 @@
+#include <Foundation/Foundation.h>
+
+@interface Foobar : NSObject
+@end
+
+void other() 
+{
+       [[Foobar alloc] init];
+}
+
+void bar() 
+{
+}
+
diff --git a/unit-tests/test-cases/archive-ObjC-unexported/foo.m b/unit-tests/test-cases/archive-ObjC-unexported/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-ObjC-unexported/main.m b/unit-tests/test-cases/archive-ObjC-unexported/main.m
new file mode 100644 (file)
index 0000000..58a039a
--- /dev/null
@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+extern void bar();
+
+int main()
+{
+       bar();
+       return 0;
+}
diff --git a/unit-tests/test-cases/archive-ObjC-unexported/main.nexp b/unit-tests/test-cases/archive-ObjC-unexported/main.nexp
new file mode 100644 (file)
index 0000000..0b864aa
--- /dev/null
@@ -0,0 +1 @@
+_bar
diff --git a/unit-tests/test-cases/archive-image_info/Makefile b/unit-tests/test-cases/archive-image_info/Makefile
new file mode 100644 (file)
index 0000000..5bb026f
--- /dev/null
@@ -0,0 +1,50 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that objc files loaded from archives set image info
+#
+
+IMAGE_INFO = "__image_info"
+
+ifeq ($(ARCH),x86_64)
+       IMAGE_INFO = "__objc_imageinfo"
+endif
+ifeq ($(ARCH),armv6)
+       IMAGE_INFO = "__objc_imageinfo"
+endif
+
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} main.m -c -o main.o
+       libtool -static main.o -o libmain.a
+       ${CC} ${CCFLAGS} libmain.a -o main -framework Foundation
+       size -l main | grep ${IMAGE_INFO} | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+       rm -rf main.o libmain.a main
diff --git a/unit-tests/test-cases/archive-image_info/main.m b/unit-tests/test-cases/archive-image_info/main.m
new file mode 100644 (file)
index 0000000..b012f44
--- /dev/null
@@ -0,0 +1,36 @@
+/* -*- 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 <Foundation/Foundation.h>
+
+@interface Foo : NSObject
+@end
+
+@implementation Foo
+@end
+
+int main()
+{
+       return 0;
+}
diff --git a/unit-tests/test-cases/bind_at_load/Makefile b/unit-tests/test-cases/bind_at_load/Makefile
new file mode 100644 (file)
index 0000000..007feb5
--- /dev/null
@@ -0,0 +1,41 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test -bind-at-load option
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib
+       ${CC} ${CCFLAGS} bar.c -dynamiclib -o libbar.dylib
+       ${CC} ${CCFLAGS} main.c libfoo.dylib libbar.dylib -o main -Wl,-bind_at_load
+       dyldinfo -lazy_bind main | grep "no compressed lazy binding info" | ${FAIL_IF_EMPTY}
+       dyldinfo -bind main | grep _bar | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} main
+       
+clean:
+       rm -f libfoo.dylib  libbar.dylib main
diff --git a/unit-tests/test-cases/bind_at_load/bar.c b/unit-tests/test-cases/bind_at_load/bar.c
new file mode 100644 (file)
index 0000000..d4a1007
--- /dev/null
@@ -0,0 +1,2 @@
+
+void bar() {}
diff --git a/unit-tests/test-cases/bind_at_load/foo.c b/unit-tests/test-cases/bind_at_load/foo.c
new file mode 100644 (file)
index 0000000..ed41e9b
--- /dev/null
@@ -0,0 +1,3 @@
+
+void foo() {}
+void foo2() {}
diff --git a/unit-tests/test-cases/bind_at_load/main.c b/unit-tests/test-cases/bind_at_load/main.c
new file mode 100644 (file)
index 0000000..7aadb5c
--- /dev/null
@@ -0,0 +1,14 @@
+#include <stddef.h>
+
+extern void foo();
+extern void foo2() __attribute__((weak_import));
+extern void bar();
+
+int main()
+{
+       foo();
+       bar();
+       if ( &foo2 != NULL )
+               foo2();
+       return 0;
+}
index 346e2b77dc3605bc05074ef831b045089f435c5f..19f0af18f6e83783b96841aa7f7e45e26737c4e1 100644 (file)
@@ -23,7 +23,7 @@
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-ALL_ARCH_OPTIONS = $(patsubst %,-arch %,$(VALID_ARCHS))
+ALL_ARCH_OPTIONS = $(patsubst %,-arch %,$(subst ppc,,$(VALID_ARCHS)) )
 
 #
 # Test that blank stubs are handled properly
@@ -34,7 +34,7 @@ run: all
 all:
 # build example fully fat dylib
 
-       gcc `echo ${ALL_ARCH_OPTIONS}` -dynamiclib foo.c -o libfoo.dylib -install_name libfoo.dylib
+       gcc `echo ${ALL_ARCH_OPTIONS}` -dynamiclib foo.c -o libfoo.dylib -install_name libfoo.dylib 
        ${FAIL_IF_BAD_MACHO} libfoo.dylib
 
        # handle the case of a native ppc compile--this sets the subtype, which must be passed to lipo
index 46472eeda5b0c1ae578489a4615f1be246a90a97..e2f7c30d024157ef91d74c13af25cb0f70ca4959 100644 (file)
@@ -35,9 +35,9 @@ run: all
 all:
        ${CC} ${CCFLAGS} foo.s -c 
        ${CC} ${CCFLAGS} bar.s -c 
-       ${CC} ${CCFLAGS} foo.o bar.o -e _foo -o foobar ${ARCH_FLAGS} -nostdlib 
+       ${CC} ${CCFLAGS} foo.o bar.o -e _foo -o foobar ${ARCH_FLAGS} -nostdlib -lSystem
        ${LD} -arch ${ARCH} -r foo.o bar.o -o foobar.o
-       ${CC} ${CCFLAGS} foobar.o -e _foo -o foobar2 ${ARCH_FLAGS} -nostdlib 
+       ${CC} ${CCFLAGS} foobar.o -e _foo -o foobar2 ${ARCH_FLAGS} -nostdlib -lSystem
        ${PASS_IFF_GOOD_MACHO} foobar
 
 clean:
diff --git a/unit-tests/test-cases/branch-interworking/Makefile b/unit-tests/test-cases/branch-interworking/Makefile
new file mode 100644 (file)
index 0000000..c83e25e
--- /dev/null
@@ -0,0 +1,42 @@
+##
+# Copyright (c) 2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+
+#
+# test thumb2 branch ranges
+#
+
+run: all
+
+
+all:
+       ${CC} ${CCFLAGS} mythumb.s -c 
+       ${CC} ${CCFLAGS} myarm.s -c 
+       ${CC} ${CCFLAGS} mythumb.o myarm.o -dynamiclib -o liball.dylib 
+       ${PASS_IFF_GOOD_MACHO} liball.dylib 
+
+clean:
+       rm  *.o liball.dylib 
diff --git a/unit-tests/test-cases/branch-interworking/myarm.s b/unit-tests/test-cases/branch-interworking/myarm.s
new file mode 100644 (file)
index 0000000..a3c7818
--- /dev/null
@@ -0,0 +1,19 @@
+
+    .text
+#if __arm__
+       .code 32
+       .align 2
+#endif 
+
+       .globl _myarm
+_myarm:
+    nop
+#if __arm__
+       //bl            _mythumb
+       b               _mythumb
+#elif __i386__ || __x86_64__
+       jmp             _mythumb
+#endif
+
+
+    .subsections_via_symbols
diff --git a/unit-tests/test-cases/branch-interworking/mythumb.s b/unit-tests/test-cases/branch-interworking/mythumb.s
new file mode 100644 (file)
index 0000000..a58c28f
--- /dev/null
@@ -0,0 +1,20 @@
+
+    .text
+#if __arm__
+       .syntax unified
+       .thumb_func _mythumb
+       .code 16
+#endif 
+
+       .globl _mythumb
+_mythumb:
+    nop
+#if __arm__
+       //bl            _myarm
+       b.w             _myarm
+#elif __i386__ || __x86_64__
+       jmp             _myarm
+#endif
+
+
+    .subsections_via_symbols
diff --git a/unit-tests/test-cases/cfstring-and-cstring/Makefile b/unit-tests/test-cases/cfstring-and-cstring/Makefile
new file mode 100644 (file)
index 0000000..6f9b150
--- /dev/null
@@ -0,0 +1,14 @@
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} foo.c bar.c -Os -o foo -framework CoreFoundation
+       ${PASS_IFF_GOOD_MACHO} foo
+
+clean:
+       rm -rf foo 
diff --git a/unit-tests/test-cases/cfstring-and-cstring/bar.c b/unit-tests/test-cases/cfstring-and-cstring/bar.c
new file mode 100644 (file)
index 0000000..3441ce9
--- /dev/null
@@ -0,0 +1,14 @@
+#include <CoreFoundation/CFString.h>
+
+
+//
+// llvm may make cfstring that has backing store of kTest
+//
+
+
+const char kTest[] = "test";
+
+void bar()
+{
+       CFStringGetLength(CFSTR("test"));
+}
diff --git a/unit-tests/test-cases/cfstring-and-cstring/foo.c b/unit-tests/test-cases/cfstring-and-cstring/foo.c
new file mode 100644 (file)
index 0000000..86b0d6e
--- /dev/null
@@ -0,0 +1,12 @@
+#include <CoreFoundation/CFString.h>
+
+extern void bar();
+
+int main() 
+{
+       CFStringGetLength(CFSTR("stuff"));
+       bar();
+       return 0; 
+}
+
+
index 39571519f31b32889c5dd5e4d9e7e950e6ea3047..272cb9f60b65bc0c23785a93185d77ba1f5fcea6 100644 (file)
@@ -1,5 +1,5 @@
 ##
-# Copyright (c) 2008-2009 Apple Inc. All rights reserved.
+# Copyright (c) 2008-2010 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
@@ -34,7 +34,7 @@ ifeq (,${findstring 64,$(ARCH)})
 else
        CFSTRING_SIZE = 64
 endif
-       USTRING_SIZE = 27
+       USTRING_SIZE = 28
 
 
 
index 72f365b72a85ce15cf583b634f6bdc7d77a4a5a9..cdfe6ac170c01f55c556fbb5585488a1f8219bd3 100644 (file)
@@ -33,7 +33,7 @@ run: all-${ARCH}
 all-ppc:
        ${PASS_IFF} true
 
-all-arm:
+all-armv6:
        ${PASS_IFF} true
        
 all-i386: all-real
index 68d809c94ef6c68deb8044667338c0f5f3cae5ff..9c9786728d60468cb663043a5fc4bea2fc8c68ce 100644 (file)
@@ -31,7 +31,7 @@ include ${TESTROOT}/include/common.makefile
 
 all:
        ${CC} ${CCFLAGS} baz.c -fno-common -c -o baz.o
-       ${CC} ${CCFLAGS} main.c foo.c bar.c baz.o -o main -mmacosx-version-min=10.5
+       ${CC} ${CCFLAGS} main.c foo.c bar.c baz.o -o main 
        nm -j -n main | grep _common > symbol.order
        ${FAIL_IF_ERROR} diff symbol.order expected.order
        ${PASS_IFF_GOOD_MACHO} main
index 4e5530410ea998186c841c39cb8bd9010d740a31..ff0919bb63341f5fd9ab2f7a493de91541046fb7 100644 (file)
@@ -33,6 +33,7 @@ run: all
 all:
        ${CC} ${CCFLAGS} main.c custom.s -o main 
        size -l main | grep __cstring | wc -l | grep 2 | ${FAIL_IF_EMPTY}
+       size -l main | grep -A2 __MYSEG | grep __cstring | grep " 10 " | ${FAIL_IF_EMPTY}
        ${PASS_IFF_GOOD_MACHO} main
 
 clean:
index 33705e52a31e24e240acbaabd6c2d5f43773b270..8871b8aa8e86db0dec97e4aae4f790f8df79436c 100644 (file)
@@ -2,7 +2,9 @@
 
 
        .section __MYSEG, __cstring, cstring_literals
-LC:            .ascii  "hello"
+LC1:           .ascii  "hello\0"
+LC2:           .ascii  "bye\0"
+LC3:           .ascii  "hello\0"
 
 
 
diff --git a/unit-tests/test-cases/cstring-empty-labeled/Makefile b/unit-tests/test-cases/cstring-empty-labeled/Makefile
new file mode 100644 (file)
index 0000000..9c3504d
--- /dev/null
@@ -0,0 +1,43 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# verify labled empty strings are preserved
+#
+#
+
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} -c foo.s -o foo.o
+       ${LD} -arch ${ARCH} -r foo.o -o foo-r.o
+       ${LD} -arch ${ARCH} -r foo-r.o -o foo-r2.o
+       ${OBJECTDUMP} foo-r.o > foo-r.dump
+       ${OBJECTDUMP} foo-r2.o > foo-r2.dump
+       ${PASS_IFF} diff foo-r.dump foo-r2.dump
+
+clean:
+       rm  foo.o foo-r.o foo-r2.o foo.dump foo-r.dump foo-r2.dump
diff --git a/unit-tests/test-cases/cstring-empty-labeled/foo.s b/unit-tests/test-cases/cstring-empty-labeled/foo.s
new file mode 100644 (file)
index 0000000..9498b53
--- /dev/null
@@ -0,0 +1,21 @@
+       .cstring
+LC2:
+       .ascii "bye\0"
+       .ascii "\0"
+       .ascii "\0"
+
+.globl _empty
+_empty:
+       .ascii "\0"
+       
+LC0:
+       .ascii "hello\0"
+       .ascii "\0"
+       .ascii "\0"
+       .ascii "\0"
+       
+LC1:
+       .ascii "\0"
+       
+       
+       .subsections_via_symbols
diff --git a/unit-tests/test-cases/custom-segment-layout/Makefile b/unit-tests/test-cases/custom-segment-layout/Makefile
new file mode 100644 (file)
index 0000000..1dfb23f
--- /dev/null
@@ -0,0 +1,16 @@
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that a large page zero works
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} main.c zero.s -o main -pagezero_size 0 -segaddr __TEXT 0xb8000000 -segaddr __MYZEROPAGE 0
+       ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+       rm -f main
diff --git a/unit-tests/test-cases/custom-segment-layout/main.c b/unit-tests/test-cases/custom-segment-layout/main.c
new file mode 100644 (file)
index 0000000..7f59a23
--- /dev/null
@@ -0,0 +1,8 @@
+
+int x = 5;
+
+int main()
+{
+       return 0;
+}
+
diff --git a/unit-tests/test-cases/custom-segment-layout/zero.s b/unit-tests/test-cases/custom-segment-layout/zero.s
new file mode 100644 (file)
index 0000000..86bde83
--- /dev/null
@@ -0,0 +1,11 @@
+
+       .section __MYZEROPAGE,_data
+_min:  .long 0
+       
+       
+       .zerofill __MYZEROPAGE,__zerofill,_padding,2147483644
+       
+       
+
+
+
diff --git a/unit-tests/test-cases/dead_strip-archive-duplicate-def/Makefile b/unit-tests/test-cases/dead_strip-archive-duplicate-def/Makefile
new file mode 100644 (file)
index 0000000..59cadd4
--- /dev/null
@@ -0,0 +1,43 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Tests that if an unused function is pulled in from an archive
+# because another function in the same .o file is needed, that the
+# first does not cause a duplicate definition error.
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} foo.c -c -o foo.o
+       ${CC} ${CCFLAGS} bar.c -c -o bar.o
+       libtool -static foo.o bar.o -o libfoobar.a
+       ${CC} ${CCFLAGS}  main.c libfoobar.a -dead_strip -o  main -Wl,-w
+       ${PASS_IFF_GOOD_MACHO} main
+       
+
+clean:
+       rm -rf main libfoobar.a foo.o bar.o
diff --git a/unit-tests/test-cases/dead_strip-archive-duplicate-def/bar.c b/unit-tests/test-cases/dead_strip-archive-duplicate-def/bar.c
new file mode 100644 (file)
index 0000000..87526e5
--- /dev/null
@@ -0,0 +1,8 @@
+
+void bar() { }
+
+int baz()
+{
+       return -1;
+}
+
diff --git a/unit-tests/test-cases/dead_strip-archive-duplicate-def/foo.c b/unit-tests/test-cases/dead_strip-archive-duplicate-def/foo.c
new file mode 100644 (file)
index 0000000..c8fcef2
--- /dev/null
@@ -0,0 +1,10 @@
+
+void foo() { }
+
+extern void bar();
+
+void deadwood()
+{
+       bar();
+}
+
diff --git a/unit-tests/test-cases/dead_strip-archive-duplicate-def/main.c b/unit-tests/test-cases/dead_strip-archive-duplicate-def/main.c
new file mode 100644 (file)
index 0000000..1f74deb
--- /dev/null
@@ -0,0 +1,14 @@
+
+extern void foo();
+
+int baz()
+{
+       return 0;
+}
+
+int main()
+{
+       foo();
+       return 0;
+}
+
diff --git a/unit-tests/test-cases/dead_strip-archive-weak-override/Makefile b/unit-tests/test-cases/dead_strip-archive-weak-override/Makefile
new file mode 100644 (file)
index 0000000..f4ed236
--- /dev/null
@@ -0,0 +1,43 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Tests that a non-weak symbol in an archive cleanly overrides
+# a weak symbol in a .o file with dead code stripping
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} foo.c -c -o foo.o
+       ${CC} ${CCFLAGS} bar.c -c -o bar.o
+       libtool -static foo.o bar.o -o libfoobar.a
+       ${CC} ${CCFLAGS}  main.c libfoobar.a -dead_strip -o main
+       nm main | grep _bar | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} main
+       
+
+clean:
+       rm -rf main foo.o bar.o libfoobar.a
diff --git a/unit-tests/test-cases/dead_strip-archive-weak-override/bar.c b/unit-tests/test-cases/dead_strip-archive-weak-override/bar.c
new file mode 100644 (file)
index 0000000..605e44e
--- /dev/null
@@ -0,0 +1,6 @@
+
+
+void bar()
+{
+}
+
diff --git a/unit-tests/test-cases/dead_strip-archive-weak-override/foo.c b/unit-tests/test-cases/dead_strip-archive-weak-override/foo.c
new file mode 100644 (file)
index 0000000..92bcb8f
--- /dev/null
@@ -0,0 +1,15 @@
+
+extern void bar();
+
+
+// strong definition of foo overrides weak definition
+// in main.c, but this foo needs bar()
+void foo() 
+{
+       bar();
+}
+
+void loadme()
+{
+}
+
diff --git a/unit-tests/test-cases/dead_strip-archive-weak-override/main.c b/unit-tests/test-cases/dead_strip-archive-weak-override/main.c
new file mode 100644 (file)
index 0000000..81362f8
--- /dev/null
@@ -0,0 +1,25 @@
+
+extern void loadme();
+
+
+void bad()
+{
+}
+
+// foo is first found be live here
+// then the use of loadme causes libfoo.a(foo.o)
+// to be loaded which overrides foo
+__attribute__((weak)) void foo()
+{
+       bad();
+}
+
+int main()
+{
+       foo();
+       loadme();
+       foo();
+       return 0;
+}
+
+
index 32ac1c5d817b7563c3dacf52bed409e7104b8fff..a2746940ce77b4b23691b9ede616807b75c3310b 100644 (file)
@@ -1,5 +1,5 @@
 ##
-# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+# Copyright (c) 2010 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
@@ -35,6 +35,7 @@ run: all
 
 all:
        ${CC} ${CCFLAGS} main.c deadwood.c -dead_strip -o main-${ARCH}
+       size -l main-${ARCH} | grep __PAGEZERO | ${FAIL_IF_EMPTY}
        ${FAIL_IF_BAD_MACHO} main-${ARCH}
        nm -j main-${ARCH} | egrep 'dead_wood|dead_door' | ${FAIL_IF_STDIN}
        ${CC} ${CCFLAGS} -dynamiclib main.c deadwood.c -dead_strip -exported_symbols_list main.exp -o dylib-${ARCH}
diff --git a/unit-tests/test-cases/demangle/Makefile b/unit-tests/test-cases/demangle/Makefile
new file mode 100644 (file)
index 0000000..6ed52b7
--- /dev/null
@@ -0,0 +1,45 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+
+#
+# Test that linker option -demangle works
+#
+
+run: all
+
+all:
+       ${CXX} ${CXXFLAGS} main.cxx -c
+       ${FAIL_IF_SUCCESS} ${LD} -arch ${ARCH} -dylib main.o -lSystem -o main 2>main1.fail
+       grep __ZN3Foo4doitEv main1.fail | ${FAIL_IF_EMPTY}
+       ${FAIL_IF_SUCCESS} ${LD} -arch ${ARCH} -dylib main.o -lSystem -demangle -o main 2>main2.fail
+       grep 'Foo::doit()' main2.fail | ${PASS_IFF_STDIN}
+       
+
+clean:
+       rm -f main.o main1.fail main2.fail main
diff --git a/unit-tests/test-cases/demangle/main.cxx b/unit-tests/test-cases/demangle/main.cxx
new file mode 100644 (file)
index 0000000..af42ca6
--- /dev/null
@@ -0,0 +1,42 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+class Foo
+{
+public:
+                       Foo() {}
+       
+       void    doit();
+};
+
+
+
+int main()
+{
+       Foo f;
+       f.doit();
+       
+       return 0;
+}
diff --git a/unit-tests/test-cases/dependency-logging/Makefile b/unit-tests/test-cases/dependency-logging/Makefile
new file mode 100644 (file)
index 0000000..e861226
--- /dev/null
@@ -0,0 +1,46 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that LD_TRACE_* work
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} foo.c -c -o foo.o
+       libtool -static foo.o -o libfoo.a
+       rm -rf trace_ars
+       export LD_TRACE_ARCHIVES=1 && export LD_TRACE_FILE=trace_ars && ${CC} ${CCFLAGS} main.c libfoo.a -o main
+       grep 'libfoo.a' trace_ars | ${FAIL_IF_EMPTY}
+       ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib
+       rm -rf trace_dylibs
+       export LD_TRACE_DYLIBS=1 && export LD_TRACE_FILE=trace_dylibs && ${CC} ${CCFLAGS} main.c libfoo.dylib -o main
+       grep 'libfoo.dylib' trace_dylibs | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} main
+       
+
+clean:
+       rm -rf foo.o libfoo.a libfoo.dylib main trace_ars trace_dylibs
diff --git a/unit-tests/test-cases/dependency-logging/foo.c b/unit-tests/test-cases/dependency-logging/foo.c
new file mode 100644 (file)
index 0000000..85e6cd8
--- /dev/null
@@ -0,0 +1 @@
+void foo() {}
diff --git a/unit-tests/test-cases/dependency-logging/main.c b/unit-tests/test-cases/dependency-logging/main.c
new file mode 100644 (file)
index 0000000..a5a79d5
--- /dev/null
@@ -0,0 +1,7 @@
+extern void foo();
+
+int main()
+{
+       foo();
+       return 0;
+}
\ No newline at end of file
diff --git a/unit-tests/test-cases/dtrace-old-probes/Makefile b/unit-tests/test-cases/dtrace-old-probes/Makefile
new file mode 100644 (file)
index 0000000..61ddb05
--- /dev/null
@@ -0,0 +1,36 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that old style _dtrace_probe$ labels are preserved
+#
+
+all: 
+       ${CC} ${CCFLAGS} main.c -o main 
+       nm main | grep _dtrace_probe | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} main
+       
+clean:
+       rm -rf main 
diff --git a/unit-tests/test-cases/dtrace-old-probes/main.c b/unit-tests/test-cases/dtrace-old-probes/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;
+}
index b7563947affb5beaf5ac5fdb52b8f58f9f608cee..935ee129f35f00d57aad3f417a1e285b5b9c8f8d 100644 (file)
@@ -1,6 +1,6 @@
 
 #include "header.h"
 
-void f() { LOTS_O_PROBES }
+void bar() { LOTS_O_PROBES }
 
 
index b59760fc02fddf18c33fd23538fa849065d8e381..1688f233744d2c2111480048b2113a2c642a677b 100644 (file)
@@ -30,7 +30,7 @@ include ${TESTROOT}/include/common.makefile
 
 all: run
 
-run: main main-r main-dead_strip libmain.dylib
+run: main main-dead_strip libmain.dylib main-r
        ${FAIL_IF_BAD_MACHO} main
        ${PASS_IFF_GOOD_MACHO} main-r
 
index 1eb6310d7ba21aaf48d2e1a6a30b29e473451fbc..9770686313fc260b6cd3f6bbf55808fbdc65dfb7 100644 (file)
@@ -1,5 +1,5 @@
 ##
-# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+# Copyright (c) 2005-2010 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
@@ -33,27 +33,16 @@ include ${TESTROOT}/include/common.makefile
 
 run: all
 
-all: foobar.o main.o 
-       ${CXX} ${CCXXFLAGS} foobar.o main.o -o dwarf-test-${ARCH}
-       ${FAIL_IF_BAD_MACHO} dwarf-test-${ARCH}
-       nm -ap dwarf-test-${ARCH} | ./stabs-filter.pl > dwarf-test-${ARCH}.stabs
-       ${PASS_IFF} diff dwarf-test-${ARCH}.stabs expected-stabs
-
-foobar.o : foo.o bar.o
+all: 
+       ${CXX} ${CCXXFLAGS} -gdwarf-2 foo.cxx -c -o foo.o -mdynamic-no-pic
+       ${CXX} ${CCXXFLAGS} -gdwarf-2 bar.cxx -c -o bar.o  -mdynamic-no-pic
        ${LD} -r -arch ${ARCH} foo.o bar.o -o foobar.o
-       ${FAIL_IF_BAD_OBJ} foobar.o
-
-foo.o : foo.cxx
-       ${CXX} ${CCXXFLAGS} -gdwarf-2 foo.cxx -c -o $@ -mdynamic-no-pic
-       ${FAIL_IF_BAD_OBJ} $@
-
-bar.o : bar.cxx
-       ${CXX} ${CCXXFLAGS} -gdwarf-2 bar.cxx -c -o $@  -mdynamic-no-pic
-       ${FAIL_IF_BAD_OBJ} $@
-
-main.o : main.cxx
-       ${CXX} ${CCXXFLAGS} -gdwarf-2 main.cxx -c -o $@ -mdynamic-no-pic
-       ${FAIL_IF_BAD_OBJ} $@
+       ${CXX} ${CCXXFLAGS} -gdwarf-2 main.cxx -c -o main.o -mdynamic-no-pic
+       ${CXX} ${CCXXFLAGS} foobar.o main.o -o main
+       ${FAIL_IF_BAD_MACHO} main
+       nm -ap main | ./stabs-filter.pl > main.stabs
+       ${PASS_IFF} diff main.stabs expected-stabs
+       
 
 clean:
-       rm -rf dwarf-test-*  *.o *.stabs
+       rm -rf foo.o bar.o main.o foobar.o main main.stabs
diff --git a/unit-tests/test-cases/dwarf-debug-notes-uuid/Makefile b/unit-tests/test-cases/dwarf-debug-notes-uuid/Makefile
new file mode 100644 (file)
index 0000000..e70c6b6
--- /dev/null
@@ -0,0 +1,45 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Verify that UUID is the same for the two binaries built
+# from the same source file but with different intermediate
+# object file paths.
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} -gdwarf-2 main.c -c -o main1.o
+       ${CC} ${CCFLAGS} -gdwarf-2 main.c -c -o main2.o
+       ${CC} ${CCFLAGS} main1.o -o main1
+       ${CC} ${CCFLAGS} main2.o -o main2
+       otool -lv main1 | grep -A3 UUID > main1.uuid
+       otool -lv main2 | grep -A3 UUID > main2.uuid
+       ${PASS_IFF} diff main1.uuid main2.uuid
+       
+
+clean:
+       rm -rf main1.o main2.o main1 main2 main1.uuid main2.uuid
diff --git a/unit-tests/test-cases/dwarf-debug-notes-uuid/main.c b/unit-tests/test-cases/dwarf-debug-notes-uuid/main.c
new file mode 100644 (file)
index 0000000..6ff8d4b
--- /dev/null
@@ -0,0 +1,23 @@
+
+
+void foo()
+{
+
+}
+
+
+void bar()
+{
+       foo();
+}
+
+
+
+int main()
+{
+       bar();
+       return 0;
+}
+
+
+
index 42f1cb72f86e7497bcc7f80b0b2c2142f0aa3055..b4fa7ab5bee2d1c514a22b937d77df09c760113f 100644 (file)
@@ -1,5 +1,5 @@
 ##
-# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+# Copyright (c) 2005-2010 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
@@ -32,19 +32,13 @@ include ${TESTROOT}/include/common.makefile
 
 run: all
 
-all: hello.o other.o 
-       ${CXX} ${CCXXFLAGS} -gdwarf-2 hello.o other.o -o dwarf-hello-${ARCH}
-       ${FAIL_IF_BAD_MACHO} dwarf-hello-${ARCH}
-       nm -ap dwarf-hello-${ARCH} | ./stabs-filter.pl > dwarf-hello-${ARCH}.stabs
-       ${PASS_IFF} diff dwarf-hello-${ARCH}.stabs expected-stabs
-
-hello.o : hello.cxx
-       ${CXX} ${CCXXFLAGS} -gdwarf-2 hello.cxx -c -o $@ -mdynamic-no-pic
-       ${FAIL_IF_BAD_OBJ} $@
-
-other.o : other.cxx
-       ${CXX} ${CCXXFLAGS} -gdwarf-2 other.cxx -c -o $@ -mdynamic-no-pic
-       ${FAIL_IF_BAD_OBJ} $@
+all:
+       ${CXX} ${CCXXFLAGS} -gdwarf-2 hello.cxx -c -o hello.o -mdynamic-no-pic
+       ${CXX} ${CCXXFLAGS} -gdwarf-2 other.cxx -c -o other.o -mdynamic-no-pic
+       ${CXX} ${CCXXFLAGS} -gdwarf-2 hello.o other.o -o hello
+       ${FAIL_IF_BAD_MACHO} hello
+       nm -ap hello | ./stabs-filter.pl > hello.stabs
+       ${PASS_IFF} diff hello.stabs expected-stabs
 
 clean:
-       rm -rf dwarf-hello-* *.o *.stabs
+       rm -rf hello hello.o other.o hello.stabs
index 0ef639ddd96f7bb7d543f2543cdd812d89a616b6..95eb33d8c859c601b7e8de180fd1b3ea981123f1 100644 (file)
@@ -7,7 +7,7 @@
 0000 ENSYM 
 0000 BNSYM 
 0000   FUN __Z3fooi
-0000   SOL header.h
+0000   SOL CWD//header.h
 0000   FUN 
 0000 ENSYM 
 0000    SO 
 0000   FUN .my_non_standard_function_name
 0000   FUN 
 0000 ENSYM 
-0000  GSYM _init
 0000 STSYM .my_non_standard_name_static
 0000 STSYM .my_non_standard_name
 0000 STSYM __ZZ3bariE8bar_init
+0000  GSYM _init
 0000  GSYM _uninit
+0000 STSYM __ZZ3bariE10bar_uninit
 0000 STSYM __ZL7suninit
 0000 STSYM __ZL5sinit
-0000 STSYM __ZZ3bariE10bar_uninit
 0000    SO 
diff --git a/unit-tests/test-cases/dwarf-strip-objc/Makefile b/unit-tests/test-cases/dwarf-strip-objc/Makefile
new file mode 100644 (file)
index 0000000..3812933
--- /dev/null
@@ -0,0 +1,29 @@
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Verify that ld -r -S preserves the __objc_imageinfo section
+#
+
+IMAGE_INFO = "__image_info"
+
+ifeq ($(ARCH),x86_64)
+       IMAGE_INFO = "__objc_imageinfo"
+endif
+ifeq ($(ARCH),armv6)
+       IMAGE_INFO = "__objc_imageinfo"
+endif
+
+
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} -gdwarf-2 hello.m -c -o hello.o
+       ${LD} -r -S hello.o -o hello-r.o
+       size -l hello-r.o | grep ${IMAGE_INFO} | ${PASS_IFF_STDIN}
+       
+       
+
+clean:
+       rm -rf hello.o hello-r.o 
diff --git a/unit-tests/test-cases/dwarf-strip-objc/hello.m b/unit-tests/test-cases/dwarf-strip-objc/hello.m
new file mode 100644 (file)
index 0000000..ffecb41
--- /dev/null
@@ -0,0 +1,8 @@
+#include <Foundation/Foundation.h>
+
+
+int main()
+{
+       [NSString stringWithUTF8String: "hello"];
+       return 0;
+}
\ No newline at end of file
index 947afa70b3b8b174a8c148468149c86e0e4eb5ef..8174f11f0af9cf005cd4063a2bba64c3b3719175 100644 (file)
@@ -31,10 +31,10 @@ include ${TESTROOT}/include/common.makefile
 run: all
 
 all:
-       ${CC} ${CCFLAGS} -gdwarf-2 hello.c -Wl,-S -o dwarf-hello-${ARCH} 
-       #${CC} ${CCFLAGS} -gdwarf-2 hello.c -o dwarf-hello-${ARCH} 
-       ${FAIL_IF_BAD_MACHO} dwarf-hello-${ARCH}
-       nm -ap dwarf-hello-${ARCH} | grep -e " - " | ${PASS_IFF_EMPTY}
+       ${CC} ${CCFLAGS} -gdwarf-2 hello.c -Wl,-S -o hello 
+       #${CC} ${CCFLAGS} -gdwarf-2 hello.c -o hello 
+       ${FAIL_IF_BAD_MACHO} hello
+       nm -ap hello | grep -e " - " | ${PASS_IFF_EMPTY}        
 
 clean:
-       rm -rf dwarf-hello-*
+       rm -rf hello hello.dSYM
index 1cf9fa023123943a96cc6f9b8c4572620b1c5d34..5ed2e91a04fff70afd1c81400d08fcbe50a13fb6 100644 (file)
@@ -31,7 +31,7 @@ include ${TESTROOT}/include/common.makefile
 run: all
 
 all: libfoo.dylib libbar.dylib libbaz.dylib
-       ${CC} ${CCFLAGS} main.c -o main -lfoo -lbar -lbaz -L.
+       ${CC} ${CCFLAGS} main.c -o main -lfoo -lbar -lbaz -L. -Wl,-w
        ${PASS_IFF_GOOD_MACHO} main
 
 libfoo.dylib : foo.c
index 617fbfc8c4d4e2d3047baff72242063c2bb366b3..057ac03730703998988b937b1045e5ae8a020880 100644 (file)
@@ -1,5 +1,5 @@
 ##
-# Copyright (c) 2007 Apple Inc. All rights reserved.
+# Copyright (c) 2007-2010 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
@@ -32,19 +32,14 @@ SHELL = bash # use bash shell so we can redirect just stderr
 
 run: all
 
-all: libfoo.dylib 
+all: 
+       mkdir -p other
+       ${CC} foo.c -dynamiclib -o other/libfoo.dylib -mmacosx-version-min=10.4
+       ${CC} bar.c -dynamiclib -o libbar.dylib other/libfoo.dylib -sub_library libfoo -mmacosx-version-min=10.4
+       ${CC} foo.c -dynamiclib -o libfoo.dylib libbar.dylib -sub_library libbar -mmacosx-version-min=10.4
        ${CC} main.c libfoo.dylib -o main -L. 2>errmsg || true
        grep "cycle" errmsg | ${PASS_IFF_STDIN}
 
-libfoo.dylib : foo.c libbar.dylib
-       ${CC} foo.c -dynamiclib -o libfoo.dylib libbar.dylib -sub_library libbar -mmacosx-version-min=10.4
-
-libbar.dylib : bar.c other/libfoo.dylib
-       ${CC} bar.c -dynamiclib -o libbar.dylib other/libfoo.dylib -sub_library libfoo -mmacosx-version-min=10.4
-
-other/libfoo.dylib : foo.c 
-       mkdir -p other
-       ${CC} foo.c -dynamiclib -o other/libfoo.dylib -mmacosx-version-min=10.4
 
 
 
diff --git a/unit-tests/test-cases/dylib-upward/Makefile b/unit-tests/test-cases/dylib-upward/Makefile
new file mode 100644 (file)
index 0000000..5248a33
--- /dev/null
@@ -0,0 +1,43 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#  Verify upward dylib options work
+
+run: all
+
+all:
+       ${CC}  ${CCFLAGS} bar.c -dynamiclib -o libbar.dylib
+       ${CC}  ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib -Wl,-upward-lbar -L.
+       otool -lv libfoo.dylib | grep -A2 LC_LOAD_UPWARD_DYLIB | grep libbar.dylib | ${FAIL_IF_EMPTY}
+       ${CC}  ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib -Wl,-upward_library,libbar.dylib
+       otool -lv libfoo.dylib | grep -A2 LC_LOAD_UPWARD_DYLIB | grep libbar.dylib | ${FAIL_IF_EMPTY}
+       mkdir -p Bar.framework
+       ${CC}  ${CCFLAGS} bar.c -dynamiclib -o Bar.framework/Bar
+       ${CC}  ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib -Wl,-upward_framework,Bar -F.
+       otool -lv libfoo.dylib | grep -A2 LC_LOAD_UPWARD_DYLIB | grep Bar.framework/Bar | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} libfoo.dylib
+
+clean:
+       rm -rf libfoo.dylib libbar.dylib Bar.framework
diff --git a/unit-tests/test-cases/dylib-upward/bar.c b/unit-tests/test-cases/dylib-upward/bar.c
new file mode 100644 (file)
index 0000000..e425999
--- /dev/null
@@ -0,0 +1 @@
+void bar() {}
diff --git a/unit-tests/test-cases/dylib-upward/foo.c b/unit-tests/test-cases/dylib-upward/foo.c
new file mode 100644 (file)
index 0000000..bf74f09
--- /dev/null
@@ -0,0 +1,6 @@
+extern void bar();
+
+void foo() 
+{
+       bar();
+}
diff --git a/unit-tests/test-cases/efi-basic/LibTest.c b/unit-tests/test-cases/efi-basic/LibTest.c
new file mode 100644 (file)
index 0000000..de051c8
--- /dev/null
@@ -0,0 +1,13 @@
+     \r
+char *gS = (void *)0;\r
+\r
+void LibInit(void)\r
+{\r
+}\r
+  \r
+\r
+void OutputString(char *String)\r
+{  \r
+       gS = String;\r
+}\r
+\r
diff --git a/unit-tests/test-cases/efi-basic/Makefile b/unit-tests/test-cases/efi-basic/Makefile
new file mode 100644 (file)
index 0000000..1f392c5
--- /dev/null
@@ -0,0 +1,73 @@
+##
+# Copyright (c) 2005-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@
+##
+
+#
+# This test verifies ld -preload support required for mtoc
+# to create a PE/COFF image that will work with EFI.
+# The mach-o file and pecoff files are parsed with the 
+# test.py script to make sure the images look OK.
+#
+# Note: We should fail with an error condition if any of the all:
+#  commands fail. 
+# Note: Currently does not support ARM due to no ARM support in 
+#  /usr/local/efi/bin/objdump
+#
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+LOCAL_CC_FLAGS = -g -Os -fshort-wchar -fno-strict-aliasing -Wall -Werror -Wno-missing-braces 
+
+#ARCH=x86_64
+#ARCH=i386
+
+
+ifeq (${ARCH},x86_64)
+  OBJ_DUMP_ARCH=efi-app-x86-64
+  LD_ARG=
+else
+  OBJ_DUMP_ARCH=efi-app-ia32
+  LD_ARG=-read_only_relocs suppress
+endif
+
+
+#
+# Compile the file
+#
+
+all: 
+       ${CC} -arch $(ARCH)  -o LibTest1.obj  $(LOCAL_CC_FLAGS) -c LibTest.c 
+       libtool -static -o LibTest1.lib LibTest1.obj
+       ${CC} -arch $(ARCH)  -o MtocTest1.obj $(LOCAL_CC_FLAGS) -c MtocTest.c 
+       libtool -static -o MtocTest1.lib MtocTest1.obj  
+       ld -arch $(ARCH)  -o MtocTest1.macho  -u __ModuleEntryPoint -e __ModuleEntryPoint $(LD_ARG) -preload -segalign 0x20 -pie -seg1addr 0x240 -map MtocTest1.map LibTest1.lib MtocTest1.lib
+       /usr/local/efi/bin/mtoc -subsystem application -align 0x20 -d MtocTest1.macho MtocTest1.macho MtocTest1.pecoff
+       otool -rR MtocTest1.macho > otool-reloc.log
+       otool -l MtocTest1.macho > otool-load.log 
+       /usr/local/efi/bin/objdump -b $(OBJ_DUMP_ARCH) -x MtocTest1.pecoff > objdump-raw.log
+       ${PASS_IFF_SUCCESS} ./mtoctest.py --arch $(ARCH)
+  
+  
+clean: 
+       rm -rf *.pecoff *.macho *.obj *.log *.lib *.map
+  
diff --git a/unit-tests/test-cases/efi-basic/MtocTest.c b/unit-tests/test-cases/efi-basic/MtocTest.c
new file mode 100644 (file)
index 0000000..5e3ebd5
--- /dev/null
@@ -0,0 +1,21 @@
+\r
+extern void LibInit(void);\r
+\r
+extern void OutputString(char *String);\r
+\r
+\r
+\r
+char * gString = "\nHello world via mtoc - reloc\n";       \r
+\r
+int gWhyAreUninitializedGlobalsBad;\r
+       \r
+\r
+void _ModuleEntryPoint(void)\r
+{ \r
+  __asm__ __volatile__ ("int $3");  \r
+\r
+  LibInit ();\r
+  gWhyAreUninitializedGlobalsBad =1;\r
+  OutputString(gString);\r
+}\r
+\r
diff --git a/unit-tests/test-cases/efi-basic/mtoctest.py b/unit-tests/test-cases/efi-basic/mtoctest.py
new file mode 100755 (executable)
index 0000000..460c8f5
--- /dev/null
@@ -0,0 +1,135 @@
+#!/usr/bin/python
+
+import sys
+import getopt
+
+def Usage():
+  print "Unkown command line args"
+  
+  
+def main():
+  try:
+    opts, args = getopt.getopt(sys.argv[1:],"hav:",["help","arch=","verbose"]) 
+  except getopt.GetoptError:
+    print "Unkown command line args"
+    sys.exit(2)
+
+  Verbose = 0
+  for o,a in opts:
+    if o in ("-h", "--help"):
+      Usage ()
+      sys.exit ()
+    elif o in ("-a", "--arch"):
+      Arch = a
+    else:
+      Usage ()
+      sys.exit ()
+    
+
+  if Verbose:
+       print "\nmach-o load commands:"
+  otoolload = open("otool-load.log", "r")
+  data = otoolload.read()
+  otoolload.close()
+  
+  
+  # extract extry point from '     ss  0x00000000 eflags 0x00000000 eip 0x00000259 cs  0x00000000'
+  if Arch == "i386":
+    eip = data.find("eip")
+    if eip != -1:
+      EntryPoint = int (data[eip + 4:eip + 4 + 10], 16)
+  
+  if Arch == "arm":
+    r15 = data.find("r15")
+    if r15 != -1:
+      EntryPoint = int (data[r15 + 4:r15 + 4 + 10], 16)
+  
+  # extract entry point from '   r15  0x0000000000000000 rip 0x0000000000000253'
+  if Arch == "x86_64":
+    rip = data.find("rip")
+    if rip != -1:
+      EntryPoint = int (data[rip + 4:rip + 4 + 18], 16)
+  
+  if EntryPoint == 0:
+    print "FAIL - no entry point for PE/COFF image"
+    sys.exit(-1)
+  else:
+       if Verbose:
+               print "Entry Point = 0x%08x" % EntryPoint
+  
+  
+  if Verbose:
+       print "\nPE/COFF dump:"
+  objdump = open("objdump-raw.log", "r")
+  data = objdump.read()
+  objdump.close()
+  
+  # Extract 'SizeOfImage               00000360'
+  Index = data.find("SizeOfImage")
+  End = data[Index:].find("\n")
+  SizeOfImage = int (data[Index+11:Index + End], 16);
+  if Verbose:
+       print "SizeOfImage = 0x%08x" % SizeOfImage
+  
+  #Parse '  0 .text         00000080  00000240  00000240  00000240  2**2'
+  #      '                  CONTENTS, ALLOC, LOAD, READONLY, CODE       '
+  EndOfTable = data.find("SYMBOL TABLE:")
+  Index = data.find("Idx Name")
+  End   = data[Index:].find("\n")
+  Index = Index + End + 1
+  
+  PeCoffEnd = 0
+  while Index < EndOfTable:
+    End   = data[Index:].find("\n")
+    Split = data[Index:Index+End].split()
+    # Split[0] Indx
+    # Split[1] Name i.e. .text
+    # Split[2] Size
+    # Split[3] VMA
+    # Split[4] LMA
+    # Split[5] File Off
+    # Split[6] Align
+    if int(Split[3],16) != int(Split[5],16):
+      print "FAIL - %s VMA %08x not equal File off %08x XIP will not work" % (Split[1], int(Split[3],16), int(Split[5],16))
+      sys.exit(-1)
+  
+    if int(Split[3],16) + int(Split[2],16) > PeCoffEnd:
+      PeCoffEnd = int(Split[3],16) + int(Split[2],16)
+    
+    if Split[1] == ".text":
+      SecStart = int(Split[3],16)
+      SecEnd = int(Split[3],16) + int(Split[2],16)
+      if (EntryPoint < SecStart) or (EntryPoint > SecEnd):
+        print "FAIL - Entry point (0x%x) not in .text section (0x%x - 0x%x)" % (EntryPoint, SecStart, SecEnd)
+        sys.exit(-1)
+    
+    if Verbose:
+               print "%10s" % Split[1] + ' ' + Split[2] + ' ' + Split[3] + ' ' + Split[4] + ' ' + Split[5] + " End = %x" % PeCoffEnd
+    Index += data[Index:].find("\n") + 1
+    Index += data[Index:].find("\n") + 1
+  
+  if SizeOfImage < PeCoffEnd:
+    print "FAIL - PE/COFF Header SizeOfImage (0x%x) is not correct. Image larger than size (0x%x)." % (SizeOfImage, PeCoffEnd)
+    sys.exit(-1)
+  
+  if Verbose:
+       print "\nmach-o relocations:"
+  otoolreloc = open("otool-reloc.log", "r")
+  lines = otoolreloc.readlines()
+  otoolreloc.close()
+  
+  found = False
+  for line in lines:
+    if found:
+      chunk = line.split()
+      if Verbose:
+        print chunk[0]
+    if line.find ("address") > -1:
+      found = True
+  
+  if Verbose:
+       print
+
+
+if __name__ == "__main__":
+    main()
index 83d18458223a28f64be574d7c8cfd9f9341b082b..59aa60d5178a30bca8df1b1ab57b74f15d4db958 100644 (file)
@@ -23,7 +23,7 @@
  */
 #include <stdio.h>
 
-// this non-seak func() will have no unwind info and no LSDA
+// this non-weak func() will have no unwind info and no LSDA
 int func() { return 0; }
 
 void foo(int x) {}
index 107400e8099a84efe62c6259ad957a42f4a5bbf9..15819f06febc9264bac2b6f5c0131d1f95c37ba7 100644 (file)
@@ -10,13 +10,13 @@ include ${TESTROOT}/include/common.makefile
 run: all
 
 all:
-       ${CXX} ${CCXXFLAGS} main.cxx -c -o main1.o -Os
+       ${CXX} ${CCXXFLAGS} main.cxx -g -c -o main1.o -Os
        #strip main1.o -u -s keep.exp -o main2.o
        ${LD} main1.o -r -x -exported_symbols_list keep.exp -o main2.o
-       ${CXX} ${CCXXFLAGS} main1.o -Wl,-x -o main1 -exported_symbols_list keep.exp
+       ${CXX} ${CCXXFLAGS} main1.o -o main1 
        ${CXX} ${CCXXFLAGS} main2.o -o main2
-       unwinddump -arch ${ARCH} main1 > main1.unwind
-       unwinddump -arch ${ARCH} main2 > main2.unwind
+       ${UNWINDDUMP} -arch ${ARCH} -no_symbols main1 > main1.unwind
+       ${UNWINDDUMP} -arch ${ARCH} -no_symbols main2 > main2.unwind
        ${PASS_IFF} diff main1.unwind main2.unwind
 
 clean:
index 325937da1bcd21151a24ce21db9e2c1bf745de20..90cb58171c401ec1eb800ee846ea3876ad225e1e 100644 (file)
 #include <stdio.h>
 #include <stdlib.h>
 
-void bar()
-{
-}
-
+int global = 0;
 
-void foo2() 
-{
-       int a = arc4random();
-       int b = arc4random();
-       fprintf(stderr, "hello %d %d\n", a, b);
+int bar() 
+{ 
+       global = 1;
+       throw 10; 
+       
 }
 
-void foo1() 
+
+void foo() 
 { 
-       foo2();
-       fprintf(stderr, "world\n");
+       try {
+               bar();
+       }
+       catch(int x) {
+               global = 2;
+               throw x;
+       }
 }
 
 
 
 int main()
 {
-       foo1();
-       bar();
-       return 0;
-}
\ No newline at end of file
+       int state = 1;
+       try {
+               state = 2;
+               foo();
+               state = 3;
+       }
+       catch (int x) {
+               if ( state != 2 )
+                       return 1;
+               if ( x != 10 )
+                       return 1;
+               state = 4;
+       }
+
+       if ( (state == 4) && (global == 2) )
+               return 0;
+       else 
+               return 1;
+}
+
index a12e7c1cbaae04eec6ecf63708591eb70680d807..504fb97f7edad058d38ec262a2fb44c5253668b3 100644 (file)
@@ -1,5 +1,5 @@
 ##
-# Copyright (c) 2009 Apple Computer, Inc. All rights reserved.
+# Copyright (c) 2010 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
@@ -25,15 +25,23 @@ include ${TESTROOT}/include/common.makefile
 
 #
 # Check that the n_sect number for __mh_dylib_header is valid when there is no __text section
+# Also check that codesigning works on empty dylib.
 #
 
+CODESIGN_ARCH = ${ARCH}
+ifeq (${ARCH},ppc)
+       CODESIGN_ARCH = ppc7400
+endif
+
+
 run: all
 
 all:
        ${CC} ${CCFLAGS} -dynamiclib justdata.c -o libjustdata.dylib -Wl,-no_compact_unwind
        ${PASS_IFF_GOOD_MACHO} libjustdata.dylib
        ${CC} ${CCFLAGS} -dynamiclib empty.c -o libempty.dylib -Wl,-no_compact_unwind
-       ${PASS_IFF_GOOD_MACHO} libempty.dylib
+       codesign_allocate -i libempty.dylib -a ${CODESIGN_ARCH} 1024 -o libsigned.dylib
+       ${PASS_IFF_GOOD_MACHO} libsigned.dylib
 
 clean:
-       rm -rf libempty.dylib libjustdata.dylib
+       rm -rf libempty.dylib libjustdata.dylib libsigned.dylib
diff --git a/unit-tests/test-cases/exported-symbols-dead_strip/Makefile b/unit-tests/test-cases/exported-symbols-dead_strip/Makefile
new file mode 100644 (file)
index 0000000..52c0d43
--- /dev/null
@@ -0,0 +1,39 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+
+#
+# Tests that link fails if undefined symbol is in export list
+#
+
+run: all
+
+all:
+       ${PASS_IFF_ERROR} ${CC} -dynamiclib foo.c -o libfoo.dylib -exported_symbols_list foo.exp -dead_strip 2>/dev/null
+       
+clean:
+       rm libfoo.dylib
diff --git a/unit-tests/test-cases/exported-symbols-dead_strip/foo.c b/unit-tests/test-cases/exported-symbols-dead_strip/foo.c
new file mode 100644 (file)
index 0000000..6bb8d95
--- /dev/null
@@ -0,0 +1,34 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2007 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stddef.h>
+
+void good() {}
+void bad() {} 
+
+
+void ABC() {}
+void ABD() { good(); }
+void DEF() {}
+void DEG() { bad(); }
+
diff --git a/unit-tests/test-cases/exported-symbols-dead_strip/foo.exp b/unit-tests/test-cases/exported-symbols-dead_strip/foo.exp
new file mode 100644 (file)
index 0000000..565684e
--- /dev/null
@@ -0,0 +1,3 @@
+_ABC
+_ABCD
+_DEF
diff --git a/unit-tests/test-cases/function-starts/Makefile b/unit-tests/test-cases/function-starts/Makefile
new file mode 100644 (file)
index 0000000..0b43cd5
--- /dev/null
@@ -0,0 +1,29 @@
+
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check -function_starts
+#
+
+run: all
+
+all:
+       # as main executable
+       ${CC} ${CCFLAGS} main.c -o main -Wl,-function_starts
+       ${DYLDINFO} -function_starts main | grep _bar | ${FAIL_IF_EMPTY}
+       # as dylib
+       ${CC} ${CCFLAGS} main.c -dynamiclib -o libmain.dylib -Wl,-function_starts
+       ${DYLDINFO} -function_starts libmain.dylib | grep _bar | ${FAIL_IF_EMPTY}
+       # as dylib with prefered load address
+       ${CC} ${CCFLAGS} main.c -dynamiclib -o libmain2.dylib -seg1addr 0x200000 -Wl,-function_starts
+       ${DYLDINFO} -function_starts libmain2.dylib | grep _bar | ${FAIL_IF_EMPTY}
+       # as dylib with aliases
+       ${CC} ${CCFLAGS} main.c -dynamiclib -o libmain3.dylib -Wl,-function_starts -Wl,-alias,_mid,midalias
+       ${DYLDINFO} -function_starts libmain3.dylib | grep _bar | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} main
+       
+
+clean:
+       rm  main libmain.dylib libmain2.dylib libmain3.dylib
diff --git a/unit-tests/test-cases/function-starts/main.c b/unit-tests/test-cases/function-starts/main.c
new file mode 100644 (file)
index 0000000..4ff1717
--- /dev/null
@@ -0,0 +1,10 @@
+
+void foo() {}
+
+void mid() {}
+
+static void bar() { foo(); }
+
+int main() { bar(); return 0; }
+
+
diff --git a/unit-tests/test-cases/hidden-r/Makefile b/unit-tests/test-cases/hidden-r/Makefile
new file mode 100644 (file)
index 0000000..702038c
--- /dev/null
@@ -0,0 +1,41 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# Tests that a hidden tentative or weak hidden symbol survives -r 
+#
+
+run: all
+
+all: 
+       ${CC} ${CCFLAGS} main.c -c -o main.o
+       ${CC} ${CCFLAGS} foo.c  -c -o foo.o
+       ${LD} -r main.o foo.o -o all.o
+       ${CC} ${CCFLAGS} all.o -o main
+       ${PASS_IFF_GOOD_MACHO} main
+       
+clean:
+       rm -f main.o foo.o all.o main
diff --git a/unit-tests/test-cases/hidden-r/foo.c b/unit-tests/test-cases/hidden-r/foo.c
new file mode 100644 (file)
index 0000000..8c03a7f
--- /dev/null
@@ -0,0 +1,5 @@
+void __attribute__((weak,visibility("hidden"))) my_weak()
+{
+}
+
+int __attribute__((visibility("hidden"))) my_tent;
diff --git a/unit-tests/test-cases/hidden-r/main.c b/unit-tests/test-cases/hidden-r/main.c
new file mode 100644 (file)
index 0000000..352c2f8
--- /dev/null
@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+extern void my_weak();
+extern int my_tent;
+
+int main()
+{
+       my_tent = 0;
+       my_weak();
+       return 0;
+}
+
index 51de101de5f49e226eb384670308fdcb96feca6d..6dfeb5c56a16e7a0beb56a8571c9fea2800d4035 100644 (file)
@@ -1,5 +1,6 @@
 #include <mach/mach_types.h>
 
+extern void extern_func();
 
 int my_global = 3;
 extern int extern_global;
@@ -7,6 +8,7 @@ extern int extern_global;
 kern_return_t mykext_start (kmod_info_t * ki, void * d) {
        ++my_global;
        ++extern_global;
+       extern_func();
     return KERN_SUCCESS;
 }
 
index a6f1537a0b827d57b3d873d181a3fb1d4c769a2d..bd9a8ff1b70ee61902be447752db9cd3c5e64231 100755 (executable)
@@ -31,7 +31,7 @@ run: all
 
 all:
        ${CC} ${CCFLAGS} foo.s -c -o foo.o
-       ${OBJECTDUMP} foo.o | grep "pointer to _end" | ${PASS_IFF_STDIN}
+       ${OBJECTDUMP} foo.o | grep "address of direct(_end)" | ${PASS_IFF_STDIN}
 
 clean:
        rm  foo.o
diff --git a/unit-tests/test-cases/large-bss/Makefile b/unit-tests/test-cases/large-bss/Makefile
new file mode 100644 (file)
index 0000000..0e5a155
--- /dev/null
@@ -0,0 +1,38 @@
+##
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that ld can link > 4GB zero fill section
+#
+
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} test.s -dynamiclib -o libtest.dylib
+       ${PASS_IFF_GOOD_MACHO} libtest.dylib
+
+clean:
+       rm -rf libtest.dylib
diff --git a/unit-tests/test-cases/large-bss/test.s b/unit-tests/test-cases/large-bss/test.s
new file mode 100644 (file)
index 0000000..c09a83c
--- /dev/null
@@ -0,0 +1,33 @@
+
+#if __x86_64__
+
+
+.lcomm _mediumarray1,4000,5
+.lcomm _bigarray1,2000000000,5
+.lcomm _bigarray2,2000000000,5
+.lcomm _bigarray3,2000000000,5
+.lcomm _small1,4,2
+.lcomm _small2,4,2
+.lcomm _small3,4,2
+       
+
+       .text
+.globl _test
+_test:
+       pushq   %rbp
+       movq    %rsp, %rbp
+       movq    _bigarray1@GOTPCREL(%rip), %rax
+       movq    _bigarray2@GOTPCREL(%rip), %rax
+       movq    _bigarray3@GOTPCREL(%rip), %rax
+       leaq    _small1(%rip),%rax
+       leaq    _small2(%rip),%rax
+       leaq    _small3(%rip),%rax
+       leaq    _mediumarray1(%rip),%rax
+       leave
+       ret
+
+
+#endif
+
+
+
index 975ad2915fe85b4346cecc6f39f096cde8d2edf5..0eb717b85eed8b30bcd514ef8763d9c1874a3e39 100644 (file)
@@ -42,4 +42,4 @@ all:
        
        
 clean:
-       rm  libfoo.dylib main rm fail.log
+       rm  -f libfoo.dylib main rm fail.log
index e3d0d6a3e2cbb2294c7ae0444f15b5f2150bd441..4f1b14dec3a9b04822036a352b87dfdcb139234c 100644 (file)
@@ -1,5 +1,5 @@
 ##
-# Copyright (c) 2008 Apple Inc. All rights reserved.
+# Copyright (c) 2008-2010 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
@@ -35,10 +35,10 @@ run: all
 all:
        ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib
        ${CC} ${CCFLAGS} main.c -Wl,-lazy_library,libfoo.dylib -o main
+       ${CC} ${CCFLAGS} main.c -lazy-lfoo -L. -o main
        ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} bad.c -Wl,-lazy_library,libfoo.dylib -o bad  2> fail.log
        ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} bad2.c -Wl,-lazy_library,libfoo.dylib -o bad2  2> fail.log
        
-       
        ${PASS_IFF_GOOD_MACHO} main
 
 clean:
diff --git a/unit-tests/test-cases/literals-labels/Makefile b/unit-tests/test-cases/literals-labels/Makefile
new file mode 100644 (file)
index 0000000..92b3535
--- /dev/null
@@ -0,0 +1,21 @@
+
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Support mulitple labels on the same literal by cloning the literal
+# into an atom per label.
+#
+
+run: all
+
+all:
+       ${CC} ${ASMFLAGS} literals.s -c -o literals.o
+       ${OBJECTDUMP} literals.o > literals.o.dump
+       ${LD} -arch ${ARCH} -r literals.o -o literals-r.o
+       ${OBJECTDUMP} literals-r.o > literals-r.o.dump
+       ${PASS_IFF} diff literals.o.dump literals-r.o.dump
+       
+clean:
+       rm -rf literals.o literals-r.o literals.o.dump  literals-r.o.dump
diff --git a/unit-tests/test-cases/literals-labels/literals.s b/unit-tests/test-cases/literals-labels/literals.s
new file mode 100644 (file)
index 0000000..1fde088
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+       .literal16
+L01:.long 12345678
+       .long 87654321
+       .long 12345678
+       .long 87654321
+               
+L02:.long 12345678
+       .long 87654321
+       .long 12345678
+       .long 87654322
+
+_foo16:
+_bar16:
+       .long 22345678
+       .long 87654321
+       .long 12345678
+       .long 87654323
+
+L04:.long 12345678
+       .long 87654321
+       .long 12345678
+       .long 87654324
+
+
+       .literal8
+L1:    .long 12345678
+       .long 87654321
+       
+L2:    .long 12345678
+       .long 87654322
+       
+_foo8:
+_bar8:
+       .long 22345678
+       .long 87654323
+       
+L4:    .long 12345678
+       .long 87654324
+       
+       .literal4       
+L11:.long 12345678
+L12:.long 12345679
+_foo4:
+_bar4:
+       .long 22345670
+L14:.long 12345671
+       
+       .cstring
+L21: .ascii "hello\0"
+L22: .ascii "hello,there\0"
+_string1:
+_string2:
+       .ascii "there\0"
+L24: .ascii "bye\0"
index 30376df977a5c76652f534a724685adb7e4dd8db..513dcccf9845c243c25a105eb6d47f67bc90a9ad 100644 (file)
@@ -251,16 +251,16 @@ seventeen:
        ${LD} -arch ${ARCH} -r a17.o b17.o -o ab17.o
        file ab17.o | grep "Mach-O" | ${PASS_IFF_EMPTY}
        # echo "verify ld -r of bitcode and mach-o produces mach-o"
-       ${LLVMGCC} ${CCFLAGS} b17.c -c -o b17.o
-       ${LD} -arch ${ARCH} -r a17.o b17.o -o ab17.o
-       file ab17.o | grep "Mach-O" | ${PASS_IFF_STDIN}
+       ${LLVMGCC} ${CCFLAGS} b17.c -c -o b17m.o
+       ${LD} -arch ${ARCH} -r a17.o b17m.o -o ab17m.o
+       file ab17m.o | grep "Mach-O" | ${PASS_IFF_STDIN}
 
 eighteen:
        #echo verify ld -r -keep_private_externs works
        ${LLVMGCC} ${CCFLAGS} --emit-llvm a18.c -c -o a18.o
        ${LD} -arch ${ARCH} -r -keep_private_externs a18.o -o a18-rkpe.o
-       ObjectDump -nm a18-rkpe.o | grep _common_hidden1 | grep " hidden" | ${FAIL_IF_EMPTY}
-       ObjectDump -nm a18-rkpe.o | grep _func_hidden2 | grep " hidden" | ${FAIL_IF_EMPTY}
+       nm -nm a18-rkpe.o | grep _common_hidden1 | grep "private external" | ${FAIL_IF_EMPTY}
+       nm -nm a18-rkpe.o | grep _func_hidden2 | grep "private external" | ${FAIL_IF_EMPTY}
        #echo verify ld -r makes hidden symbols internal (except for commons)
        ${LD} -arch ${ARCH} -r a18.o -o a18-r.o
        #ObjectDump -nm a18-r.o | grep _common_hidden1 | grep " hidden" | ${FAIL_IF_EMPTY}
index 3cd06fd69b9c370dd971d7cef1c77bf3dd1c759e..1b8d4bf3eeecddc5f425a8615a64bdc9e570ecae 100644 (file)
@@ -2,3 +2,11 @@
 int a = 0;
 int func_a() { return a; }
 
+// add code that will cause stack canary 
+extern void fill(char*);
+void test()
+{
+       char buf[100];
+       fill(buf);
+}
+
diff --git a/unit-tests/test-cases/lto-dead_strip-objc/Makefile b/unit-tests/test-cases/lto-dead_strip-objc/Makefile
new file mode 100644 (file)
index 0000000..ccd5b59
--- /dev/null
@@ -0,0 +1,41 @@
+##
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# <rdar://problem/8481987> Link Time Optimization crashes linker with 'dead code strip' + hidden symbol
+#
+
+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 foo.m  -c -o foo.o -fvisibility=hidden
+       ${LLVMGCC} ${CCFLAGS} -dynamiclib foo.o -o libfoo.dylib -dead_strip -framework Foundation
+       ${PASS_IFF_GOOD_MACHO} libfoo.dylib
+       
+clean:
+       rm -f foo.o libfoo.dylib
diff --git a/unit-tests/test-cases/lto-dead_strip-objc/foo.m b/unit-tests/test-cases/lto-dead_strip-objc/foo.m
new file mode 100644 (file)
index 0000000..6ee5735
--- /dev/null
@@ -0,0 +1,27 @@
+#include <Foundation/Foundation.h>
+
+@interface Foo : NSObject
+- (NSString*) foo;
+@end
+
+
+@implementation Foo
+- (NSString*) foo
+{
+       return [NSString stringWithUTF8String:"hello"];
+}
+@end
+
+
+@interface Bar : NSData
+- (NSArray*) bar;
+@end
+
+
+@implementation Bar
+- (NSArray*) bar
+{
+       return [NSArray array];
+}
+@end
+
diff --git a/unit-tests/test-cases/lto-dead_strip-some-hidden/Makefile b/unit-tests/test-cases/lto-dead_strip-some-hidden/Makefile
new file mode 100644 (file)
index 0000000..d563c92
--- /dev/null
@@ -0,0 +1,41 @@
+##
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# <rdar://problem/8481987> Link Time Optimization crashes linker with 'dead code strip' + hidden symbol
+#
+
+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 bar.c  -c -o bar.o -fvisibility=hidden
+       ${LLVMGCC} ${CCFLAGS} -dynamiclib bar.o -o libbar.dylib -dead_strip
+       ${PASS_IFF_GOOD_MACHO} libbar.dylib
+       
+clean:
+       rm  bar.o libbar.dylib
diff --git a/unit-tests/test-cases/lto-dead_strip-some-hidden/bar.c b/unit-tests/test-cases/lto-dead_strip-some-hidden/bar.c
new file mode 100644 (file)
index 0000000..480ac85
--- /dev/null
@@ -0,0 +1,19 @@
+
+int data[] = { 4, 5, 6 };
+int deaddata[] = { 7, 8, 9 };
+
+int func() { return 0; }
+int deadfunc() { return 0; }
+
+__attribute__((visibility("default")))
+int* foo()
+{
+       return data;
+}
+
+__attribute__((visibility("default")))
+void* foo2()
+{
+       return func;
+}
+
diff --git a/unit-tests/test-cases/lto-dead_strip-tentative/Makefile b/unit-tests/test-cases/lto-dead_strip-tentative/Makefile
new file mode 100644 (file)
index 0000000..fa0a02b
--- /dev/null
@@ -0,0 +1,44 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# <rdar://problem/8708091> Link Time Optimization error with tentative defs and -dead_strip
+#
+
+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 foo.c -c -o foo.o 
+       ${LLVMGCC} ${CCFLAGS} --emit-llvm bar.c -c -o bar.o 
+       ${LLVMGCC} ${CCFLAGS} --emit-llvm baz.c -c -o baz.o 
+       ${LLVMGCC} ${CCFLAGS} main.c -c -o main.o 
+       ${LLVMGCC} ${CCFLAGS} main.o foo.o bar.o baz.o -o main -dead_strip
+       ${PASS_IFF_GOOD_MACHO} main
+       
+clean:
+       rm -rf foo.o bar.o baz.o main.o main
diff --git a/unit-tests/test-cases/lto-dead_strip-tentative/bar.c b/unit-tests/test-cases/lto-dead_strip-tentative/bar.c
new file mode 100644 (file)
index 0000000..d8fb526
--- /dev/null
@@ -0,0 +1,4 @@
+
+int tent;
+
+int bar() { return tent; }
diff --git a/unit-tests/test-cases/lto-dead_strip-tentative/baz.c b/unit-tests/test-cases/lto-dead_strip-tentative/baz.c
new file mode 100644 (file)
index 0000000..d1cca6e
--- /dev/null
@@ -0,0 +1,5 @@
+
+int tent;
+
+int baz() { return tent; }
+
diff --git a/unit-tests/test-cases/lto-dead_strip-tentative/foo.c b/unit-tests/test-cases/lto-dead_strip-tentative/foo.c
new file mode 100644 (file)
index 0000000..983fe9c
--- /dev/null
@@ -0,0 +1,4 @@
+
+int tent;
+
+int foo() { return tent; }
diff --git a/unit-tests/test-cases/lto-dead_strip-tentative/main.c b/unit-tests/test-cases/lto-dead_strip-tentative/main.c
new file mode 100644 (file)
index 0000000..4138be7
--- /dev/null
@@ -0,0 +1,12 @@
+
+extern int foo();
+extern int bar();
+extern int baz();
+
+int main()
+{
+       foo();
+       bar();
+       baz();
+       return 0;
+}
diff --git a/unit-tests/test-cases/lto-dead_strip-unused/Makefile b/unit-tests/test-cases/lto-dead_strip-unused/Makefile
new file mode 100644 (file)
index 0000000..a518d82
--- /dev/null
@@ -0,0 +1,43 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# <rdar://problem/7438246> LTO with 'dead code strip' can't ignore unused functions with undefined references
+#
+
+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 bar.c  -c -o bar.o
+       ${LLVMGCC} ${CCFLAGS} --emit-llvm main.c -c -o main.o 
+       ${LLVMGCC} ${CCFLAGS} -dead_strip main.o bar.o -o main
+       ${PASS_IFF_GOOD_MACHO} main
+       
+clean:
+       rm -f bar.o main.o main
+       
diff --git a/unit-tests/test-cases/lto-dead_strip-unused/bar.c b/unit-tests/test-cases/lto-dead_strip-unused/bar.c
new file mode 100644 (file)
index 0000000..f5f5823
--- /dev/null
@@ -0,0 +1,15 @@
+
+
+void bar() 
+{
+}
+
+
+extern void unused1();
+
+void unused2()
+{
+       unused1();
+}
+
+
diff --git a/unit-tests/test-cases/lto-dead_strip-unused/main.c b/unit-tests/test-cases/lto-dead_strip-unused/main.c
new file mode 100644 (file)
index 0000000..f04d475
--- /dev/null
@@ -0,0 +1,8 @@
+extern void bar();
+
+int main()
+{
+       bar();
+       return 0;
+}
+
diff --git a/unit-tests/test-cases/lto-objc-image-info/Makefile b/unit-tests/test-cases/lto-objc-image-info/Makefile
new file mode 100644 (file)
index 0000000..8b13444
--- /dev/null
@@ -0,0 +1,53 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# <rdar://problem/8198537> trivial Objective-C app fails when using libLTO
+#
+
+LLVMGCC = /Developer/usr/bin/llvm-gcc-4.2 -arch ${ARCH}
+LLVMGXX = /Developer/usr/bin/llvm-g++-4.2 -arch ${ARCH}
+
+
+IMAGE_INFO = "__image_info"
+
+ifeq ($(ARCH),x86_64)
+       IMAGE_INFO = "__objc_imageinfo"
+endif
+ifeq ($(ARCH),armv6)
+       IMAGE_INFO = "__objc_imageinfo"
+endif
+
+
+run: all
+
+all:
+       ${LLVMGCC} ${CCFLAGS} --emit-llvm main.m -c -o main.o
+       ${LLVMGCC} ${CCFLAGS} main.o -o main -framework Foundation
+       size -l main | grep ${IMAGE_INFO} | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} main
+       
+clean:
+       rm -rf main  main.o
diff --git a/unit-tests/test-cases/lto-objc-image-info/main.m b/unit-tests/test-cases/lto-objc-image-info/main.m
new file mode 100644 (file)
index 0000000..7b88000
--- /dev/null
@@ -0,0 +1,9 @@
+
+#include <Foundation/Foundation.h>
+
+int main() {
+  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+  [pool drain];
+  return 0;
+}
+
diff --git a/unit-tests/test-cases/lto-object_path/Makefile b/unit-tests/test-cases/lto-object_path/Makefile
new file mode 100644 (file)
index 0000000..aeda85d
--- /dev/null
@@ -0,0 +1,42 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that linker option -object_path_lto results in tmp .o file
+# being produced.
+#
+
+LLVMGCC = /Developer/usr/bin/llvm-gcc-4.2 -arch ${ARCH}
+
+run: all
+
+all:
+       ${LLVMGCC} ${CCFLAGS} --emit-llvm main.c -c -o main.o -fvisibility=hidden
+       ${LLVMGCC} ${CCFLAGS} main.o -o main -Wl,-object_path_lto,`pwd`/main.tmp.o
+       nm main.tmp.o | grep _main | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} main
+       
+clean:
+       rm  main  main.o main.tmp.o main 
diff --git a/unit-tests/test-cases/lto-object_path/main.c b/unit-tests/test-cases/lto-object_path/main.c
new file mode 100644 (file)
index 0000000..578d24b
--- /dev/null
@@ -0,0 +1,15 @@
+
+#include <stdio.h>
+
+
+void foo(int x)
+{
+       printf("hello, world %d\n", x);
+}
+
+int main()
+{
+       foo(10);
+       return 0;
+}
+
index 03756ffa258d6b4a85e0547876ad8440760db9d1..784ba44d818d79b2f9b7089f1ef4ec979904244c 100644 (file)
@@ -1,5 +1,5 @@
 ##
-# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+# Copyright (c) 2006-2010 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
@@ -30,9 +30,11 @@ include ${TESTROOT}/include/common.makefile
 run: all
 
 all:
-       ${CC} main.c -o main-${ARCH} -exported_symbols_list main.exp
-       ${FAIL_IF_BAD_MACHO} main-${ARCH}
-       nm -m main-${ARCH} | grep _magicSymbol | grep "referenced dynamically" | ${PASS_IFF_STDIN}
+       ${CC} main.c -o main -exported_symbols_list main.exp
+       nm -m main | grep _magicSymbol | grep "referenced dynamically" | ${FAIL_IF_EMPTY}
+       nm -m main | grep _hiddenSymbol | grep "referenced dynamically" | ${FAIL_IF_STDIN}
+       ${PASS_IFF_GOOD_MACHO} main
+       
 
 clean:
-       rm  main-*
+       rm  main
index 1e71f1b2a25c8e4cc969ba42a2761f7dc22b8cc0..13046158d1a7387454012c681c5c2cdabfcf16c2 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
  *
- * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2006-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -27,6 +27,9 @@
 int  magicSymbol = 1;
 asm(".desc _magicSymbol, 0x10");
 
+// this symbol will be suppressed by .exp file
+int  hiddenSymbol = 1;
+asm(".desc _hiddenSymbol, 0x10");
 
 int main()
 {
index 4eb9e89d39c8b5ccd7521b445ac896ab050181c4..1c7daa3a756db2753aaa33727e6c7fcfda78b27d 100644 (file)
@@ -1 +1,2 @@
 _main
+_magicSymbol
index 5d525530388298356b7003eb8a345f8e12dd7771..7c5304bd090343ef0ed094f48f87a94cc0f422fb 100644 (file)
@@ -47,8 +47,8 @@ all:
        ${FAIL_IF_BAD_MACHO} foo
        ${OTOOL} -hlv foo | grep LC_UUID | ${FAIL_IF_STDIN}
 
-# Test ld -r of stabs file has no uuid
-       ${CC} ${CCFLAGS} foo.c -c -o foo.o -gfull -gstabs+
+# 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}
 
index d581048691b2f4f19510e57181911abeb3e5f396..3d594fddedf9926a8daaf4524b500e026daa1957 100644 (file)
@@ -38,6 +38,8 @@ all-i386: hasnl
 
 all-armv6: hasnl
 
+all-armv7: hasnl
+
 all-x86_64: all-true
 
 all-true:
@@ -49,15 +51,18 @@ hasnl:
        ${CC} ${CCFLAGS} -c other.c -o other.o
        ${LD} -r -arch ${ARCH} foo.o other.o -o fooall.o -exported_symbol _foo
        # make sure there  are two indirect symbols: _foo and LOCAL
-       otool -Iv fooall.o | grep "3 entries" | ${FAIL_IF_EMPTY}
+       otool -Iv fooall.o | grep "4 entries" | ${FAIL_IF_EMPTY}
        otool -Iv fooall.o | grep _foo   | ${FAIL_IF_EMPTY}
        otool -Iv fooall.o | grep _tent  | ${FAIL_IF_EMPTY}
        otool -Iv fooall.o | grep _other | ${FAIL_IF_STDIN}
-       # make sure re-parsed correctly
-       ${OBJECTDUMP} fooall.o | grep name: | grep '_foo$$non_lazy_ptr' | ${FAIL_IF_EMPTY} 
-       ${OBJECTDUMP} fooall.o | grep name: | grep '_other$$non_lazy_ptr' | ${FAIL_IF_EMPTY}
-       ${OBJECTDUMP} fooall.o | grep name: | grep '_tent$$non_lazy_ptr' | ${FAIL_IF_EMPTY}
-       ${PASS_IFF} true
+       ${OBJECTDUMP} fooall.o | grep name: | grep 'non-lazy-pointer-to:_foo' | ${FAIL_IF_EMPTY} 
+       ${OBJECTDUMP} fooall.o | grep name: | grep 'non-lazy-pointer-to-local:_other' | ${FAIL_IF_EMPTY}
+       ${OBJECTDUMP} fooall.o | grep name: | grep 'non-lazy-pointer-to:_tent' | ${FAIL_IF_EMPTY}
+       ${OBJECTDUMP} fooall.o | grep name: | grep 'non-lazy-pointer-to:_foo' | ${FAIL_IF_EMPTY}
+       ${LD} -r -arch ${ARCH} fooall.o -o fooall2.o 
+       ${OBJECTDUMP} fooall.o > fooall.dump
+       ${OBJECTDUMP} fooall2.o > fooall2.dump
+       ${PASS_IFF} diff fooall.dump fooall2.dump
        
 clean:
-       rm -rf *.o
+       rm -rf *.o fooall.dump fooall2.dump
index 9d21475cec62bac18798e8072e91eba9e0aeacc5..bfde3dedbf48fe20abc0cdfcd3d5658b7a854b09 100644 (file)
@@ -15,3 +15,6 @@ extern int tent;
 
 int gettent() { return tent; }
 
+
+extern void* func;
+void* getfunc() { return func; }
index 68eb01dd53c76623ad8cf2b003e133410866418d..8ee4784affbf1893063d3b5900757262453d0add 100644 (file)
@@ -1,3 +1,4 @@
 int foo = 2;
 int other = 3;
 int tent;
+void func() {}
diff --git a/unit-tests/test-cases/non-lazy-sections-r/Makefile b/unit-tests/test-cases/non-lazy-sections-r/Makefile
new file mode 100644 (file)
index 0000000..020cd0a
--- /dev/null
@@ -0,0 +1,55 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that non-lazy-pointers in different section are properly handled by -r
+#
+
+
+all: all-${ARCH}
+
+all-ppc: hasnl
+
+all-i386: hasnl
+
+all-armv6: hasnl
+
+all-armv7: hasnl
+
+all-x86_64: all-true
+
+all-true:
+       ${PASS_IFF} true
+
+
+hasnl:
+       ${CC} ${CCFLAGS} -c foo.s -o foo.o
+       ${LD} -r -arch ${ARCH} foo.o -o foo-r.o 
+       ${OBJECTDUMP} foo.o > foo.o.dump 
+       ${OBJECTDUMP} foo-r.o > foo-r.o.dump 
+       ${PASS_IFF} diff foo.o.dump foo-r.o.dump
+       
+clean:
+       rm -rf *.o *.dump
diff --git a/unit-tests/test-cases/non-lazy-sections-r/foo.s b/unit-tests/test-cases/non-lazy-sections-r/foo.s
new file mode 100644 (file)
index 0000000..d307880
--- /dev/null
@@ -0,0 +1,34 @@
+       .text
+       .globl  _test
+_test:
+#if __i386__
+       movl    L_foo$non_lazy_ptr, %eax
+       movl    L_bar$non_lazy_ptr, %eax
+       movl    L_other$non_lazy_ptr, %eax
+       ret
+#endif
+#if __arm__ || __ppc__
+       .long   L_foo$non_lazy_ptr
+       .long   L_bar$non_lazy_ptr
+       .long   L_other$non_lazy_ptr
+#endif
+
+
+
+       .section        __IMPORT,__pointers,non_lazy_symbol_pointers
+L_foo$non_lazy_ptr:
+.indirect_symbol _foo
+       .long   0
+       
+       .section        __DATA,__one,non_lazy_symbol_pointers
+L_bar$non_lazy_ptr:
+.indirect_symbol _bar
+       .long   0
+       
+       .section        __DATA,__two,non_lazy_symbol_pointers
+L_other$non_lazy_ptr:
+.indirect_symbol _other
+       .long   0
+
+
+.subsections_via_symbols
diff --git a/unit-tests/test-cases/objc-abi/Makefile b/unit-tests/test-cases/objc-abi/Makefile
new file mode 100644 (file)
index 0000000..d7eb660
--- /dev/null
@@ -0,0 +1,49 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Verify -objc_abi_version 2 works for i386
+#
+ifeq (${ARCH},i386)
+       ALL = all-i386
+else
+       ALL = all
+endif
+
+run: ${ALL}
+
+all:
+       ${PASS_IFF_GOOD_MACHO} /usr/bin/true
+
+all-i386:
+       ${CC} ${CCFLAGS} test.m -framework Foundation -o test1
+       size -l test1 | grep __image_info | ${FAIL_IF_EMPTY}
+       ${CC} ${CCFLAGS} test.m -fobjc-abi-version=2 -Wl,-objc_abi_version,2 -framework Foundation -o test2
+       size -l test2 | grep __objc_imageinfo | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} test2
+       
+       
+clean:
+       rm -rf test1 test2
diff --git a/unit-tests/test-cases/objc-abi/test.m b/unit-tests/test-cases/objc-abi/test.m
new file mode 100644 (file)
index 0000000..8b4a295
--- /dev/null
@@ -0,0 +1,17 @@
+
+@interface Foo 
+@end
+
+@implementation Foo
+@end
+
+
+int main()
+{
+       return 0;
+}
+
+
+#if __i386__ && __OBJC2__
+       int _objc_empty_vtable = 1;
+#endif
diff --git a/unit-tests/test-cases/objc-category-archive/Makefile b/unit-tests/test-cases/objc-category-archive/Makefile
new file mode 100644 (file)
index 0000000..b56bacf
--- /dev/null
@@ -0,0 +1,27 @@
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# Verify -ObjC works with x86_64 categories
+# Verify stripped archives keep don't-strip bit
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} -g test.m -c -o test.o
+       libtool -static test.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
+       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}
+       ${PASS_IFF_GOOD_MACHO} main2
+       
+clean:
+       rm -rf test.o test-stripped.o libtest.a libtest-stripped.a main main2 
diff --git a/unit-tests/test-cases/objc-category-archive/main.m b/unit-tests/test-cases/objc-category-archive/main.m
new file mode 100644 (file)
index 0000000..1105885
--- /dev/null
@@ -0,0 +1,6 @@
+
+int main()
+{
+  return 0;
+}
+
diff --git a/unit-tests/test-cases/objc-category-archive/test.m b/unit-tests/test-cases/objc-category-archive/test.m
new file mode 100644 (file)
index 0000000..5347856
--- /dev/null
@@ -0,0 +1,21 @@
+
+#include <Foundation/Foundation.h>
+
+int some_global_to_stop_libtool_warning = 5;
+
+@interface NSObject (stuff)
+- (void) mycatmethod1;
+@end
+
+@implementation NSObject (stuff)
+- (void) mycatmethod1 { }
+@end
+
+@interface NSObject (other)
+- (void) mycatmethod2;
+@end
+
+@implementation NSObject (other)
+- (void) mycatmethod2 { }
+@end
+
diff --git a/unit-tests/test-cases/objc-category-optimize-load/Makefile b/unit-tests/test-cases/objc-category-optimize-load/Makefile
new file mode 100644 (file)
index 0000000..5652312
--- /dev/null
@@ -0,0 +1,52 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Verify optimization where categories are merged into classes
+#
+OPTIONS = 
+
+ifeq ($(ARCH),i386)
+       OPTIONS = -fobjc-abi-version=2 -Wl,-objc_abi_version,2
+endif
+
+all:   all-${ARCH}
+
+all-ppc:
+       ${PASS_IFF} true
+
+all-i386: all-rest
+all-x86_64: all-rest
+all-armv6: all-rest
+
+all-rest:
+       # check optimzation of category methods
+       ${CC} ${CCFLAGS} ${OPTIONS} -dynamiclib foo.m cat1.m  -framework Foundation -o libfoo.dylib
+       size -l libfoo.dylib | grep "__objc_catlist:" | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} libfoo.dylib
+       
+       
+clean:
+       rm -rf libfoo.dylib
diff --git a/unit-tests/test-cases/objc-category-optimize-load/cat1.m b/unit-tests/test-cases/objc-category-optimize-load/cat1.m
new file mode 100644 (file)
index 0000000..06a78f0
--- /dev/null
@@ -0,0 +1,15 @@
+#include <Foundation/Foundation.h>
+
+@interface Foo : NSObject
+-(void) method1;
+@end
+
+
+@interface Foo(mycat)
++(void) load;
+@end
+
+@implementation Foo(mycat)
++(void) load {}
+@end
+
diff --git a/unit-tests/test-cases/objc-category-optimize-load/foo.m b/unit-tests/test-cases/objc-category-optimize-load/foo.m
new file mode 100644 (file)
index 0000000..065450c
--- /dev/null
@@ -0,0 +1,9 @@
+#include <Foundation/Foundation.h>
+
+@interface Foo : NSObject
+@end
+
+
+@implementation Foo
+@end
+
diff --git a/unit-tests/test-cases/objc-category-optimize/Makefile b/unit-tests/test-cases/objc-category-optimize/Makefile
new file mode 100644 (file)
index 0000000..c452bec
--- /dev/null
@@ -0,0 +1,71 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Verify optimization where categories are merged into classes
+#
+OPTIONS = 
+
+ifeq ($(ARCH),i386)
+       OPTIONS = -fobjc-abi-version=2 -Wl,-objc_abi_version,2
+endif
+
+all:   all-${ARCH}
+
+all-ppc:
+       ${PASS_IFF} true
+
+all-i386: all-rest
+all-x86_64: all-rest
+all-armv6: all-rest
+
+all-rest:
+       # check optimization can be turned off
+       ${CC} ${CCFLAGS} ${OPTIONS} -dynamiclib foo.m cat1.m cat2.m -framework Foundation -Wl,-no_objc_category_merging -o libno.dylib
+       size -l libno.dylib | grep "__objc_catlist: 0" | ${FAIL_IF_STDIN}
+       otool -ov libno.dylib | grep -A17 __objc_classlist | grep -A16 '_OBJC_CLASS_$$_Foo' | grep "count 1" | ${FAIL_IF_EMPTY}
+       # check optimzation of category methods
+       ${CC} ${CCFLAGS} ${OPTIONS} -dynamiclib foo.m cat1.m cat2.m -framework Foundation -o libfoo.dylib
+       size -l libfoo.dylib | grep "__objc_catlist: 0" | ${FAIL_IF_EMPTY}
+       otool -ov libfoo.dylib | grep -A20 __objc_classlist | grep -A20 '_OBJC_CLASS_$$_Foo' | grep "count 4" | ${FAIL_IF_EMPTY}
+       # check optimzation of protocol and category methods
+       ${CC} ${CCFLAGS} ${OPTIONS} -dynamiclib foo.m cat1.m cat2.m -DPROTOCOLS -framework Foundation -o libfoo2.dylib
+       size -l libfoo2.dylib | grep "__objc_catlist: 0" | ${FAIL_IF_EMPTY}
+       otool -ov libfoo2.dylib | grep -A20 __objc_classlist | grep -A20 '_OBJC_CLASS_$$_Foo' | grep "count 6" | ${FAIL_IF_EMPTY}
+       # check optimzation of properties and category methods
+       ${CC} ${CCFLAGS} ${OPTIONS} -dynamiclib foo.m cat1.m cat2.m -DPROPERTIES -framework Foundation -o libfoo3.dylib
+       size -l libfoo3.dylib | grep "__objc_catlist: 0" | ${FAIL_IF_EMPTY}
+       otool -ov libfoo3.dylib | grep -A20 __objc_classlist | grep -A20 '_OBJC_CLASS_$$_Foo' | grep "count 6" | ${FAIL_IF_EMPTY}
+       # check optimzation of category methods and no base methods
+       ${CC} ${CCFLAGS} ${OPTIONS} -dynamiclib foo.m cat1.m cat2.m -DNO_BASE_METHODS -framework Foundation -o libfoo4.dylib
+       size -l libfoo4.dylib | grep "__objc_catlist: 0" | ${FAIL_IF_EMPTY}
+       otool -ov libfoo4.dylib | grep -A20 __objc_classlist | grep -A20 '_OBJC_CLASS_$$_Foo' | grep "count 3" | ${FAIL_IF_EMPTY}
+       otool -ov libfoo4.dylib | grep -A20 "Meta Class" | grep "count 2" | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} libfoo3.dylib
+       
+       
+       
+clean:
+       rm -rf  lib*.dylib
diff --git a/unit-tests/test-cases/objc-category-optimize/cat1.m b/unit-tests/test-cases/objc-category-optimize/cat1.m
new file mode 100644 (file)
index 0000000..11c170b
--- /dev/null
@@ -0,0 +1,29 @@
+#include <Foundation/Foundation.h>
+
+@interface Foo : NSObject
+-(void) method1;
+@end
+
+
+
+
+@interface Foo(mycat)
+-(void) instance_method_mycat1;
+-(void) instance_method_mycat2;
++(void) class_method_mycat;
+#if PROPERTIES
+       @property(readonly) int property1;
+       @property(readonly) int property2;
+#endif
+@end
+
+@implementation Foo(mycat)
+-(void) instance_method_mycat1 {}
+-(void) instance_method_mycat2 {}
++(void) class_method_mycat {}
+#if PROPERTIES
+       -(int) property1 { return 0; }
+       -(int) property2 { return 0; }
+#endif
+@end
+
diff --git a/unit-tests/test-cases/objc-category-optimize/cat2.m b/unit-tests/test-cases/objc-category-optimize/cat2.m
new file mode 100644 (file)
index 0000000..7b51291
--- /dev/null
@@ -0,0 +1,37 @@
+#include <Foundation/Foundation.h>
+
+@interface Foo : NSObject
+-(void) method1;
+@end
+
+#if PROTOCOLS
+       @protocol myotherprotocol
+       - (void) instance_method_myotherprotocol1;
+       - (void) instance_method_myotherprotocol2;
+       @end
+
+       @interface Foo(myothercat) < myotherprotocol >
+       - (void) instance_method_myothercat;
+       + (void) class_method_myothercat;
+       @end
+
+       @implementation Foo(myothercat)
+       - (void) instance_method_myothercat {} 
+       + (void) class_method_myothercat {}
+       - (void) instance_method_myotherprotocol1 {} 
+       - (void) instance_method_myotherprotocol2 {}
+       @end
+
+#else
+       @interface Foo(myothercat)
+       - (void) instance_method_myothercat;
+       + (void) class_method_myothercat;
+       @end
+
+       @implementation Foo(myothercat)
+       - (void) instance_method_myothercat {} 
+       + (void) class_method_myothercat {}
+       @end
+#endif
+
+
diff --git a/unit-tests/test-cases/objc-category-optimize/foo.m b/unit-tests/test-cases/objc-category-optimize/foo.m
new file mode 100644 (file)
index 0000000..0509927
--- /dev/null
@@ -0,0 +1,17 @@
+#include <Foundation/Foundation.h>
+
+@interface Foo : NSObject
+#ifndef NO_BASE_METHODS
+-(void) instance_method;
++(void) class_method;
+#endif
+@end
+
+
+@implementation Foo
+#ifndef NO_BASE_METHODS
+-(void) instance_method {}
++(void) class_method {}
+#endif
+@end
+
diff --git a/unit-tests/test-cases/objc-class-alias/Makefile b/unit-tests/test-cases/objc-class-alias/Makefile
new file mode 100644 (file)
index 0000000..c8c1b27
--- /dev/null
@@ -0,0 +1,44 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Verify -alias works with ObjC classes
+#
+CLASS_NAME_FOO = .objc_class_name_Foo
+ifeq (${ARCH},x86_64)
+       CLASS_NAME_FOO = '_OBJC_CLASS_$$_Foo'
+endif
+
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} test.m -Wl,-alias,${CLASS_NAME_FOO},_MagicName -framework Foundation -o test
+       ${DYLDINFO} -export test | grep ${CLASS_NAME_FOO} | awk '{ print $$1}' > foo.addr
+       ${DYLDINFO} -export test | grep _MagicName | awk '{ print $$1}' > magic.addr
+       ${PASS_IFF} diff foo.addr magic.addr 
+       
+clean:
+       rm -rf test foo.addr  magic.addr
diff --git a/unit-tests/test-cases/objc-class-alias/test.m b/unit-tests/test-cases/objc-class-alias/test.m
new file mode 100644 (file)
index 0000000..7eba08f
--- /dev/null
@@ -0,0 +1,13 @@
+#include <Foundation/Foundation.h>
+
+@interface Foo : NSObject
+@end
+
+@implementation Foo
+@end
+
+
+int main()
+{
+       return 0;
+}
index 0abe7d5996037b04488a5198d064da2dd3debc5d..b18012a23030dcdb8d0629d90d1e2a62f5c4a359 100644 (file)
@@ -26,6 +26,16 @@ include ${TESTROOT}/include/common.makefile
 SHELL = bash # use bash shell so we can redirect just stderr
 
 
+IMAGE_INFO = "__image_info"
+
+ifeq ($(ARCH),x86_64)
+       IMAGE_INFO = "__objc_imageinfo"
+endif
+ifeq ($(ARCH),armv6)
+       IMAGE_INFO = "__objc_imageinfo"
+endif
+
+
 
 #
 # Validate that the linker catches illegal combinations of .o files 
@@ -70,6 +80,11 @@ test:
        ${FAIL_IF_BAD_MACHO} libfoobar.dylib
        otool -o libfoobar.dylib | grep -A4 _image | grep flags | grep 0x[26]  | ${FAIL_IF_STDIN}
 
+       # check GC/RR + RR -> RR
+       ${CC} ${CCFLAGS} bar-gc.o foo.o runtime.c -dynamiclib -o libfoobar.dylib 
+       ${FAIL_IF_BAD_MACHO} libfoobar.dylib
+       otool -o libfoobar.dylib | grep -A4 _image | grep flags | grep 0x[26]  | ${FAIL_IF_STDIN}
+
        # check GC + GC/RR -> GC
        ${CC} ${CCFLAGS} foo-gc-only.o bar-gc.o runtime.c -dynamiclib -o libfoobar.dylib  
        ${FAIL_IF_BAD_MACHO} libfoobar.dylib
@@ -78,7 +93,42 @@ test:
        # check RR + GC -> error
        ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} foo.o bar-gc-only.o runtime.c -dynamiclib -o libfoobar.dylib 2> fail.log
 
+       # check cmd line GC/RR, GC/RR + RR -> error
+       ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} foo-gc.o foo.o runtime.c -dynamiclib -o libfoobar.dylib -Wl,-objc_gc 2> fail.log
+       
+       # check GC/RR + compaction
+       ${CC} ${CCFLAGS} foo-gc.o bar-gc.o runtime.c -dynamiclib -Wl,-objc_gc_compaction -o libfoobar.dylib 
+       otool -o libfoobar.dylib | grep -A4 _image | grep flags | grep 0x12  | ${FAIL_IF_EMPTY}
+
+       # check GC + compaction
+       ${CC} ${CCFLAGS} foo-gc-only.o bar-gc-only.o runtime.c -dynamiclib -Wl,-objc_gc_compaction -o libfoobar.dylib 
+       otool -o libfoobar.dylib | grep -A4 _image | grep flags | grep 0x16  | ${FAIL_IF_EMPTY}
+
+       # none + GC/RR-dylib -> none
+       ${CC} ${CCFLAGS} foo-gc.o runtime.c -dynamiclib -o libfoo.dylib 
+       ${CC} ${CCFLAGS} none.c libfoo.dylib -dynamiclib -o libnone.dylib
+       size -l libnone.dylib | grep ${IMAGE_INFO} | ${FAIL_IF_STDIN}
+
+       # none + GC-dylib -> none
+       ${CC} ${CCFLAGS} foo-gc-only.o runtime.c -dynamiclib -o libfoo.dylib 
+       ${CC} ${CCFLAGS} none.c libfoo.dylib -dynamiclib -o libnone.dylib
+       size -l libnone.dylib | grep ${IMAGE_INFO} | ${FAIL_IF_STDIN}
+
+       # none + RR-dylib -> none
+       ${CC} ${CCFLAGS} foo.o runtime.c -dynamiclib -o libfoo.dylib 
+       ${CC} ${CCFLAGS} none.c libfoo.dylib -dynamiclib -o libnone.dylib
+       size -l libnone.dylib | grep ${IMAGE_INFO} | ${FAIL_IF_STDIN}
+
+       # check RR + GC-dylib -> error
+       ${CC} ${CCFLAGS} foo-gc-only.o runtime.c -dynamiclib -o libfoo.dylib 
+       ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} bar.o runtime.c -dynamiclib libfoo.dylib -o libbar.dylib 2> fail.log
+
+       # check GC + RR-dylib -> error
+       ${CC} ${CCFLAGS} foo.o runtime.c -dynamiclib -o libfoo.dylib 
+       ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} bar-gc-only.o runtime.c -dynamiclib libfoo.dylib -o libbar.dylib 2> fail.log
+
+
        ${PASS_IFF} true
 
 clean:
-       rm -rf foo*.o bar*.o libfoobar.dylib fail.log
+       rm -rf foo*.o bar*.o libfoobar.dylib fail.log libfoo.dylib libnone.dylib
diff --git a/unit-tests/test-cases/objc-gc-checks/none.c b/unit-tests/test-cases/objc-gc-checks/none.c
new file mode 100644 (file)
index 0000000..44506fa
--- /dev/null
@@ -0,0 +1 @@
+void none() {}
index c0b908146bc752c7b3ec53db270b16338288e54f..6596f83c5bfa91183c47ff6ac54d64e6ea4f41c4 100644 (file)
@@ -36,10 +36,10 @@ run: all
 
 all:
        ${CC} ${CCFLAGS} test.m -c -o test.o
-       ${OBJECTDUMP}  -no_content test.o | grep -v zero-fill-at> test.dump
+       ${OBJECTDUMP}  -no_content test.o > test.dump
 
        ${LD} -arch ${ARCH} -r test.o -keep_private_externs -o test-r.o
-       ${OBJECTDUMP}  -no_content test-r.o | grep -v zero-fill-at > test-r.dump
+       ${OBJECTDUMP}  -no_content test-r.o  > test-r.dump
 
        diff test.dump test-r.dump | ${PASS_IFF_EMPTY}
        
diff --git a/unit-tests/test-cases/objc-properties/Makefile b/unit-tests/test-cases/objc-properties/Makefile
new file mode 100644 (file)
index 0000000..999bf2f
--- /dev/null
@@ -0,0 +1,19 @@
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# Verify an Objective-C object file when run through ld -r is unaltered.
+#
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} test.m -dynamiclib -framework Foundation -o libtest.dylib
+       ${CC} ${CCFLAGS} test.m -dynamiclib -framework Foundation -o libtest.dylib -Wl,-no_compact_linkedit -ldylib1.o
+       ${PASS_IFF_GOOD_MACHO} libtest.dylib
+       
+clean:
+       rm -rf libtest.dylib
diff --git a/unit-tests/test-cases/objc-properties/test.m b/unit-tests/test-cases/objc-properties/test.m
new file mode 100644 (file)
index 0000000..25ca8c8
--- /dev/null
@@ -0,0 +1,49 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <Foundation/Foundation.h>
+
+@interface Test
+{
+       BOOL            one;
+       NSString*       two;                    
+       BOOL            three;  
+}
+@property                              BOOL            one;
+@property (retain)             NSString*       two;
+@property                              BOOL            three;
+@end
+
+
+@implementation Test
+@synthesize one;
+@synthesize two;
+@synthesize three;
+@end
+
+
+int main()
+{
+       return 0;
+}
diff --git a/unit-tests/test-cases/objc-visibility/Makefile b/unit-tests/test-cases/objc-visibility/Makefile
new file mode 100644 (file)
index 0000000..bd0eb15
--- /dev/null
@@ -0,0 +1,42 @@
+##
+# 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
+
+
+#
+# Tests when a hidden class is made file scoped (via ld -r)
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} foo.m -c -o foo.o
+       ${CC} ${CCFLAGS} bar.m -c -o bar.o
+       ${CC} ${CCFLAGS} foo.o bar.o -dynamiclib -o libtfoobar.dylib -framework Foundation
+       ${LD} -r -arch ${ARCH} foo.o bar.o -o bar2.o
+       ${CC} ${CCFLAGS} bar2.o -dynamiclib -o liball.dylib -framework Foundation
+       ${PASS_IFF_GOOD_MACHO} liball.dylib
+
+clean:
+       rm -rf *.o *.dylib
diff --git a/unit-tests/test-cases/objc-visibility/bar.h b/unit-tests/test-cases/objc-visibility/bar.h
new file mode 100644 (file)
index 0000000..dc37fe1
--- /dev/null
@@ -0,0 +1,8 @@
+
+#include <Foundation/Foundation.h>
+
+__attribute__((visibility("hidden")))
+@interface Bar : NSData 
+- (NSArray*) bar;
+@end
+
diff --git a/unit-tests/test-cases/objc-visibility/bar.m b/unit-tests/test-cases/objc-visibility/bar.m
new file mode 100644 (file)
index 0000000..997ac26
--- /dev/null
@@ -0,0 +1,13 @@
+#include <Foundation/Foundation.h>
+
+
+#include "bar.h"
+
+
+@implementation Bar
+- (NSArray*) bar
+{
+       return [NSArray array];
+}
+@end
+
diff --git a/unit-tests/test-cases/objc-visibility/foo.h b/unit-tests/test-cases/objc-visibility/foo.h
new file mode 100644 (file)
index 0000000..e22d744
--- /dev/null
@@ -0,0 +1,8 @@
+
+#include <Foundation/Foundation.h>
+
+
+@interface Foo : NSObject
+- (NSString*) foo;
+@end
+
diff --git a/unit-tests/test-cases/objc-visibility/foo.m b/unit-tests/test-cases/objc-visibility/foo.m
new file mode 100644 (file)
index 0000000..4882e7b
--- /dev/null
@@ -0,0 +1,14 @@
+
+#include <Foundation/Foundation.h>
+
+#include "foo.h"
+#include "bar.h"
+
+@implementation Foo
+- (NSString*) foo
+{
+       [Bar alloc];
+       return [NSString stringWithUTF8String:"hello"];
+}
+@end
+
index b3c1edd783ff9f83f6c49dccc47a45ba154ef397..4ae8026a8c58b912f60ddf063e89c863a4722cf1 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
  *
- * Copyright (c) 2007-2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2007-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -55,5 +55,9 @@ namespace wow {
 
 int main()
 {
+       wow::inner();
+       baz(NULL);
+       bar(NULL);
+       foo();
        return 0;
 }
index 21ae0ea15196d1a25bb41f783412af2c40325cf8..1aec6f13ff0797c056464327a1784f0abb5ba341 100644 (file)
@@ -33,25 +33,29 @@ include ${TESTROOT}/include/common.makefile
 run: all
 
 all:
-       as -arch ${ARCH} -L extra.s -o extra.o
-       ${CC} ${CCFLAGS} main.c extra.o -o main1 -Wl,-order_file -Wl,main1.order 
+       ${CC} ${CCFLAGS} main.c extra.s -o main1 -Wl,-order_file -Wl,main1.order 
        ${FAIL_IF_BAD_MACHO} main1
        nm -n -g -j main1 | grep "_main" > main1.nm
        ${PASS_IFF} diff main1.nm main1.expected
 
-       ${CC} ${CCFLAGS} main.c extra.o -o main2 -Wl,-order_file -Wl,main2.order 
+       ${CC} ${CCFLAGS} main.c extra.s -o main2 -Wl,-order_file -Wl,main2.order 
        ${FAIL_IF_BAD_MACHO} main2
        nm -n -j main2 | egrep '^_[a-z]+[0-9]$$' > main2.nm
        ${PASS_IFF} diff main2.nm main2.expected
 
-       ${CC} -arch ${ARCH} -c main.c -o main.o
-       ${CC} ${CCFLAGS} main.o extra.o -o main3 -Wl,-order_file -Wl,main3.order 
+       ${CC} ${CCFLAGS} main.c -c -o main.o
+       ${CC} ${CCFLAGS} main.o extra.s -o main3 -Wl,-order_file -Wl,main3.order 
        ${FAIL_IF_BAD_MACHO} main3
        nm -n -g -j main3 | grep "_main" > main3.nm
        ${PASS_IFF} diff main3.nm main3.expected
 
+       ${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
+       ${PASS_IFF} diff main4.nm main4.expected
+
 
 
 
 clean:
-       rm -rf main1 *.nm main2 *.o warnings.log main3
+       rm -rf main1 main2 main3 main4 main.o *.nm
index 90166cedbcfa1dc847f289faf28a336b74a3af16..eba52c08a52e00032fae86f6436a6094863e8df2 100644 (file)
@@ -7,6 +7,8 @@ _foo1: nop
 
        .globl _aaa2
 _aaa2:
+       .globl _bbb2
+       .private_extern _bbb2
 _bbb2:
 _ccc2:
        nop
@@ -20,5 +22,7 @@ _ccc3:
 
 _aaa4:
        nop
-       
-       
\ No newline at end of file
+
+#if SUBSECTIONS
+       .subsections_via_symbols
+#endif
diff --git a/unit-tests/test-cases/order_file/main4.expected b/unit-tests/test-cases/order_file/main4.expected
new file mode 100644 (file)
index 0000000..b82a23d
--- /dev/null
@@ -0,0 +1,6 @@
+_aaa2
+_main3
+_main2
+_main4
+_foo1
+_bbb3
diff --git a/unit-tests/test-cases/order_file/main4.order b/unit-tests/test-cases/order_file/main4.order
new file mode 100644 (file)
index 0000000..fe07188
--- /dev/null
@@ -0,0 +1,4 @@
+
+
+_bbb2
+_main3
diff --git a/unit-tests/test-cases/re-export-and-use/Makefile b/unit-tests/test-cases/re-export-and-use/Makefile
new file mode 100644 (file)
index 0000000..b220580
--- /dev/null
@@ -0,0 +1,54 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that a public re-exported library is automatically added as a dependent
+# unless nothing is used from it.
+#
+
+
+run: all
+
+all:
+
+       ${CC} ${CCFLAGS} -dynamiclib pub.c -o libpub.dylib  -install_name /usr/lib/libpub.dylib
+       ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib 
+       ${CC} ${CCFLAGS} -dynamiclib baz.c -o libbaz.dylib  
+       # verify uses of symbols from re-exported dylibs have ordinal that allows dyld to search amoung re-exported dylibs 
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -DUSE_BAZ -o libfoo2.dylib -Wl,-reexport_library libpub.dylib -Wl,-reexport_library libbar.dylib  -Wl,-reexport_library libbaz.dylib 
+       dyldinfo -bind      libfoo2.dylib | grep _bar | grep this-image | ${FAIL_IF_EMPTY}
+       dyldinfo -lazy_bind libfoo2.dylib | grep _bar | grep this-image | ${FAIL_IF_EMPTY}
+       dyldinfo -bind      libfoo2.dylib | grep _baz | grep this-image | ${FAIL_IF_EMPTY}
+       dyldinfo -lazy_bind libfoo2.dylib | grep _baz | grep this-image | ${FAIL_IF_EMPTY}
+       # verify that if only one non-publc re-exported dylib, don't use magic ordinal
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo1.dylib -Wl,-reexport_library libpub.dylib -Wl,-reexport_library libbar.dylib 
+       dyldinfo -bind      libfoo1.dylib | grep _bar | grep this-image | ${FAIL_IF_STDIN}
+       dyldinfo -lazy_bind libfoo1.dylib | grep _bar | grep this-image | ${FAIL_IF_STDIN}
+       ${PASS_IFF_GOOD_MACHO} libfoo2.dylib
+
+
+clean:
+
+       rm -rf libbar.dylib libbaz.dylib libpub.dylib libfoo1.dylib libfoo2.dylib  
diff --git a/unit-tests/test-cases/re-export-and-use/bar.c b/unit-tests/test-cases/re-export-and-use/bar.c
new file mode 100644 (file)
index 0000000..642a280
--- /dev/null
@@ -0,0 +1,5 @@
+
+int bar()
+{
+       return 1;
+}
diff --git a/unit-tests/test-cases/re-export-and-use/baz.c b/unit-tests/test-cases/re-export-and-use/baz.c
new file mode 100644 (file)
index 0000000..98b7832
--- /dev/null
@@ -0,0 +1,5 @@
+
+int baz()
+{
+       return 1;
+}
diff --git a/unit-tests/test-cases/re-export-and-use/foo.c b/unit-tests/test-cases/re-export-and-use/foo.c
new file mode 100644 (file)
index 0000000..ad634d3
--- /dev/null
@@ -0,0 +1,16 @@
+extern int bar();
+extern int baz();
+
+void* pbar = &bar;
+
+#if USE_BAZ
+void* pbaz = &baz;
+#endif
+
+int foo()
+{
+#if USE_BAZ
+       baz();
+#endif
+       return bar();
+}
diff --git a/unit-tests/test-cases/re-export-and-use/pub.c b/unit-tests/test-cases/re-export-and-use/pub.c
new file mode 100644 (file)
index 0000000..03ffc1b
--- /dev/null
@@ -0,0 +1,5 @@
+
+int pub()
+{
+       return 1;
+}
diff --git a/unit-tests/test-cases/re-export-layers/Makefile b/unit-tests/test-cases/re-export-layers/Makefile
new file mode 100644 (file)
index 0000000..fc62273
--- /dev/null
@@ -0,0 +1,61 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test all the different ways that re-exports can be specified and implemented
+#
+
+
+run: all
+
+all:
+
+
+# -reexport_library for 10.4
+       ${CC} ${CCFLAGS} -dynamiclib baz.c -o libbaz.dylib  -mmacosx-version-min=10.4
+       ${FAIL_IF_BAD_MACHO} libbaz.dylib
+       ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib -Wl,-reexport_library,libbaz.dylib -mmacosx-version-min=10.4
+       ${FAIL_IF_BAD_MACHO} libbar.dylib
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-reexport_library,libbar.dylib -mmacosx-version-min=10.4
+       ${FAIL_IF_BAD_MACHO} libfoo.dylib
+       ${CC} ${CCFLAGS} main.c libfoo.dylib -o main
+       ${FAIL_IF_BAD_MACHO} main
+
+       
+# -reexport_library for 10.5 and later
+       ${CC} ${CCFLAGS} -dynamiclib baz.c -o libbaz.dylib  
+       ${FAIL_IF_BAD_MACHO} libbaz.dylib
+       ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib -Wl,-reexport_library,libbaz.dylib 
+       ${FAIL_IF_BAD_MACHO} libbar.dylib
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-reexport_library,libbar.dylib 
+       ${FAIL_IF_BAD_MACHO} libfoo.dylib
+       ${CC} ${CCFLAGS} main.c libfoo.dylib -o main
+       ${PASS_IFF_GOOD_MACHO} main
+
+
+clean:
+
+       rm -rf  libbaz.dylib libbar.dylib libfoo.dylib main
+       
diff --git a/unit-tests/test-cases/re-export-layers/bar.c b/unit-tests/test-cases/re-export-layers/bar.c
new file mode 100644 (file)
index 0000000..9c18401
--- /dev/null
@@ -0,0 +1,5 @@
+
+int bar (void)
+{
+       return 1;
+}
diff --git a/unit-tests/test-cases/re-export-layers/baz.c b/unit-tests/test-cases/re-export-layers/baz.c
new file mode 100644 (file)
index 0000000..af6a9f8
--- /dev/null
@@ -0,0 +1,5 @@
+
+int baz (void)
+{
+  return 1;
+}
diff --git a/unit-tests/test-cases/re-export-layers/foo.c b/unit-tests/test-cases/re-export-layers/foo.c
new file mode 100644 (file)
index 0000000..d0cdf47
--- /dev/null
@@ -0,0 +1,4 @@
+int foo (void)
+{
+  return 1;
+}
diff --git a/unit-tests/test-cases/re-export-layers/main.c b/unit-tests/test-cases/re-export-layers/main.c
new file mode 100644 (file)
index 0000000..5f1fae9
--- /dev/null
@@ -0,0 +1,15 @@
+
+
+extern void baz();
+extern void bar();
+extern void foo();
+
+
+int main()
+{
+       baz();
+       bar();
+       foo();
+       return 0;
+}
+
diff --git a/unit-tests/test-cases/re-export-symbol/Makefile b/unit-tests/test-cases/re-export-symbol/Makefile
new file mode 100644 (file)
index 0000000..6de347c
--- /dev/null
@@ -0,0 +1,56 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that fine grain re-exports works
+#
+
+run: all
+
+all:
+       # build base library
+       ${CC} ${CCFLAGS} -dynamiclib bar.c -o `pwd`/libbar.dylib
+       ${FAIL_IF_BAD_MACHO} libbar.dylib
+
+       # build library the re-exports _bar from base library
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib libbar.dylib -exported_symbols_list foo.exp
+       ${FAIL_IF_BAD_MACHO} libfoo.dylib
+       ${DYLDINFO} -export libfoo.dylib | grep _bar | grep 're-export' | ${FAIL_IF_EMPTY}
+       # link against dylib and verify _bar is marked as coming from libfoo
+       ${CC} ${CCFLAGS} main1.c libfoo.dylib -o main1
+       ${DYLDINFO}  -bind -lazy_bind main1 | grep _bar | grep libfoo | ${FAIL_IF_EMPTY}
+
+       # build library the re-exports _bar from base library as _mybar
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo2.dylib libbar.dylib -Wl,-alias,_bar,_mybar -exported_symbols_list foo2.exp
+       ${FAIL_IF_BAD_MACHO} libfoo2.dylib
+       ${DYLDINFO} -export libfoo2.dylib | grep _mybar | grep 're-export' | grep _bar | ${FAIL_IF_EMPTY} 
+       # link against dylib and verify _mybar is marked as coming from libfoo
+       ${CC} ${CCFLAGS} main2.c libfoo2.dylib -o main2
+       ${DYLDINFO}  -bind -lazy_bind main2 | grep _mybar | grep libfoo2 | ${FAIL_IF_EMPTY}
+       
+       ${PASS_IFF_GOOD_MACHO} libfoo2.dylib 
+       
+clean:
+       rm -rf libbar.dylib libfoo.dylib libfoo2.dylib main1 main2
diff --git a/unit-tests/test-cases/re-export-symbol/bar.c b/unit-tests/test-cases/re-export-symbol/bar.c
new file mode 100644 (file)
index 0000000..34e5666
--- /dev/null
@@ -0,0 +1,5 @@
+
+int bar(void)
+{
+  return 1;
+}
diff --git a/unit-tests/test-cases/re-export-symbol/foo.c b/unit-tests/test-cases/re-export-symbol/foo.c
new file mode 100644 (file)
index 0000000..714540a
--- /dev/null
@@ -0,0 +1,4 @@
+int foo(void)
+{
+  return 1;
+}
diff --git a/unit-tests/test-cases/re-export-symbol/foo.exp b/unit-tests/test-cases/re-export-symbol/foo.exp
new file mode 100644 (file)
index 0000000..b9e50b8
--- /dev/null
@@ -0,0 +1,2 @@
+_foo
+_bar
diff --git a/unit-tests/test-cases/re-export-symbol/foo2.exp b/unit-tests/test-cases/re-export-symbol/foo2.exp
new file mode 100644 (file)
index 0000000..d55b748
--- /dev/null
@@ -0,0 +1,2 @@
+_foo
+_mybar
diff --git a/unit-tests/test-cases/re-export-symbol/main1.c b/unit-tests/test-cases/re-export-symbol/main1.c
new file mode 100644 (file)
index 0000000..4c0b25e
--- /dev/null
@@ -0,0 +1,9 @@
+extern int foo();
+extern int bar();
+
+int main()
+{
+       foo();
+       bar();
+       return 0;
+}
diff --git a/unit-tests/test-cases/re-export-symbol/main2.c b/unit-tests/test-cases/re-export-symbol/main2.c
new file mode 100644 (file)
index 0000000..edac057
--- /dev/null
@@ -0,0 +1,10 @@
+extern int foo();
+extern int mybar();
+
+int main()
+{
+       foo();
+       mybar();
+       return 0;
+}
+
index 02ed1df488fe0a782073bbf0f8e860134f59c7ef..8db5b0384fd6876c07827d77117e97bb8642b3ba 100644 (file)
@@ -32,15 +32,24 @@ SHELL = bash # use bash shell so we can redirect just stderr
 
 NO_PIC =  
 STATIC =  
+RELOC_FAIL = ${FAIL_IF_SUCCESS}
+LRELOCS_NEEDED = ${FAIL_IF_EMPTY}
+XRELOCS_NEEDED = ${FAIL_IF_EMPTY}
 
 ifeq (${ARCH},i386)
        NO_PIC =  -mdynamic-no-pic
        STATIC =  -static
-else 
-       ifeq (${ARCH},ppc)
-               NO_PIC =  -mdynamic-no-pic
-               STATIC =  -mdynamic-no-pic
-       endif
+endif
+ifeq (${ARCH},ppc)
+       NO_PIC =  -mdynamic-no-pic
+       STATIC =  -mdynamic-no-pic
+       XRELOCS_NEEDED =  ${FAIL_IF_STDIN}
+       LRELOCS_NEEDED =  ${FAIL_IF_EMPTY}
+endif
+ifeq (${ARCH},x86_64)
+       RELOC_FAIL =  
+       XRELOCS_NEEDED =  ${FAIL_IF_STDIN}
+       LRELOCS_NEEDED =  ${FAIL_IF_STDIN}
 endif
 
 
@@ -48,16 +57,25 @@ endif
 all:
        # build libfoo.dylib as regular dylib
        ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib
+       # build libtest.dylib using -mdynamic-no-pic, should fail
+       ${CC} ${CCFLAGS} test_rebase.c -c ${NO_PIC}
+       ${RELOC_FAIL} ${CC} ${CCFLAGS} test_rebase.o libfoo.dylib -dynamiclib -o libtestrebase.dylib -read_only_relocs error 2>/dev/null
+       ${CC} ${CCFLAGS} test_bind.c -c ${NO_PIC}
+       ${RELOC_FAIL} ${CC} ${CCFLAGS} test_bind.o libfoo.dylib -dynamiclib -o libtestbind.dylib -read_only_relocs error 2>/dev/null
        # build libtest.dylib using -mdynamic-no-pic and -read_only_relocs suppress
-       ${CC} ${CCFLAGS} test.c -c ${NO_PIC}
-       ${CC} ${CCFLAGS} test.o libfoo.dylib -dynamiclib -o libtest.dylib -read_only_relocs suppress -Wl,-w
+       ${CC} ${CCFLAGS} test_rebase.c -c ${NO_PIC}
+       ${CC} ${CCFLAGS} test_bind.c -c ${NO_PIC}
+       ${CC} ${CCFLAGS} test_rebase.o test_bind.o libfoo.dylib -dynamiclib -o libtest-no-pic.dylib -read_only_relocs suppress -Wl,-w
        # build libtest.dylib using -static and -read_only_relocs suppress
-       ${CC} ${CCFLAGS} test.c -c ${STATIC}
-       ${CC} ${CCFLAGS} test.o libfoo.dylib -dynamiclib -o libtest.dylib -read_only_relocs suppress -Wl,-w
+       ${CC} ${CCFLAGS} test_rebase.c -c ${STATIC}
+       ${CC} ${CCFLAGS} test_bind.c -c ${STATIC}
+       ${CC} ${CCFLAGS} test_rebase.o test_bind.o libfoo.dylib -dynamiclib -o libtest-static.dylib -read_only_relocs suppress -Wl,-w
+       otool -lv libtest-static.dylib | grep -A9 "sectname __text" | grep attributes | grep EXT_RELOC | ${XRELOCS_NEEDED}
+       otool -lv libtest-static.dylib | grep -A9 "sectname __text" | grep attributes | grep LOC_RELOC | ${LRELOCS_NEEDED}
        # build main using -static and -read_only_relocs suppress
-       ${CC} ${CCFLAGS} test.c -c ${STATIC}
-       ${CC} ${CCFLAGS} test.o libfoo.dylib -o foo -read_only_relocs suppress -Wl,-w
-       ${PASS_IFF_GOOD_MACHO} foo
+       ${CC} ${CCFLAGS} main.c -c ${STATIC}
+       ${CC} ${CCFLAGS} main.o libfoo.dylib -o main -read_only_relocs suppress -Wl,-w
+       ${PASS_IFF_GOOD_MACHO} main
 
 clean:
-       rm -rf test.o libfoo.dylib libtest.dylib foo
+       rm -rf test_bind.o test_rebase.o libfoo.dylib libtestrebase.dylib libtestbind.dylib libtest-no-pic.dylib libtest-static.dylib main.o main
diff --git a/unit-tests/test-cases/read-only-relocs/main.c b/unit-tests/test-cases/read-only-relocs/main.c
new file mode 100644 (file)
index 0000000..d5fe9c2
--- /dev/null
@@ -0,0 +1,10 @@
+
+extern int b;
+extern void func();
+
+int main() 
+{ 
+       func();
+       return b; 
+}
+
diff --git a/unit-tests/test-cases/read-only-relocs/test_bind.c b/unit-tests/test-cases/read-only-relocs/test_bind.c
new file mode 100644 (file)
index 0000000..8ec6b8d
--- /dev/null
@@ -0,0 +1,10 @@
+
+extern int b;
+extern void func();
+
+int test_bind() 
+{ 
+       func();
+       return b; 
+}
+
diff --git a/unit-tests/test-cases/read-only-relocs/test_rebase.c b/unit-tests/test-cases/read-only-relocs/test_rebase.c
new file mode 100644 (file)
index 0000000..1ddf43c
--- /dev/null
@@ -0,0 +1,8 @@
+
+int a=0; 
+
+int test_rebase() 
+{ 
+       return a; 
+}
+
index 9373aa3679b9f85db1386d308f5e0ab2495a1480..cc7407b065f59e27540a220341d91c3efe2a8ff1 100644 (file)
@@ -1,5 +1,5 @@
 ##
-# Copyright (c) 2006-2008 Apple Inc. All rights reserved.
+# Copyright (c) 2006-2010 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
@@ -32,10 +32,10 @@ include ${TESTROOT}/include/common.makefile
 run: all
 
 all:
-       ${CC} ${CCFLAGS} -c foo.c -o foo.${ARCH}.o
+       ${CC} ${CCFLAGS} -c -g foo.c -o foo.${ARCH}.o
        ${FAIL_IF_BAD_OBJ} foo.${ARCH}.o
 
-       ${CC} ${CCFLAGS} -c bar.m -o bar.${ARCH}.o
+       ${CC} ${CCFLAGS} -c -g bar.m -o bar.${ARCH}.o
        ${FAIL_IF_BAD_OBJ} bar.${ARCH}.o
 
        ${CC} ${CCFLAGS} foo.${ARCH}.o bar.${ARCH}.o -dynamiclib -Wl,-no_uuid -Wl,-no_order_data -o libfoo.${ARCH}.dylib -framework Foundation  -framework CoreFoundation 
diff --git a/unit-tests/test-cases/reexport_symbols_list/Makefile b/unit-tests/test-cases/reexport_symbols_list/Makefile
new file mode 100644 (file)
index 0000000..abc560c
--- /dev/null
@@ -0,0 +1,61 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+#
+# Test -reexport_symbols_list 
+#
+
+run: all
+
+all:
+       # build base library
+       ${CC} ${CCFLAGS} -dynamiclib bar.c -o `pwd`/libbar.dylib
+       ${FAIL_IF_BAD_MACHO} libbar.dylib
+
+       # verify re-export fails with -bundle
+       ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} -bundle foo.c -o libfoo.bundle libbar.dylib -Wl,-reexported_symbols_list,bart.exp 2>/dev/null
+       
+       # verify failure if re-exported symbol does not exist
+       ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib libbar.dylib -Wl,-reexported_symbols_list,junk.exp 2>/dev/null
+       
+       # verify failure if re-exported symbol is from .o file
+       ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib libbar.dylib -Wl,-reexported_symbols_list,foo.exp 2>/dev/null
+       
+       # build library the re-exports _bart from base library
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib libbar.dylib -Wl,-reexported_symbols_list,bart.exp
+       ${FAIL_IF_BAD_MACHO} libfoo.dylib
+       ${DYLDINFO} -export libfoo.dylib | grep _barb | ${FAIL_IF_STDIN}
+       ${DYLDINFO} -export libfoo.dylib | grep _bart | grep 're-export' | ${FAIL_IF_EMPTY}
+       
+       # link against dylib and verify _bart is marked as coming from libfoo
+       ${CC} ${CCFLAGS} main1.c libfoo.dylib -o main1
+       ${DYLDINFO} -bind -lazy_bind main1 | grep _bart | grep libfoo | ${FAIL_IF_EMPTY}
+
+       ${PASS_IFF_GOOD_MACHO} libfoo.dylib
+       
+clean:
+       rm -rf libbar.dylib libfoo.dylib main1 
diff --git a/unit-tests/test-cases/reexport_symbols_list/bar.c b/unit-tests/test-cases/reexport_symbols_list/bar.c
new file mode 100644 (file)
index 0000000..b0f6fc9
--- /dev/null
@@ -0,0 +1,10 @@
+
+int barb(void)
+{
+       return 1;
+}
+
+int bart(void)
+{
+       return 0;
+}
diff --git a/unit-tests/test-cases/reexport_symbols_list/bart.exp b/unit-tests/test-cases/reexport_symbols_list/bart.exp
new file mode 100644 (file)
index 0000000..da8ec30
--- /dev/null
@@ -0,0 +1 @@
+_bart
diff --git a/unit-tests/test-cases/reexport_symbols_list/foo.c b/unit-tests/test-cases/reexport_symbols_list/foo.c
new file mode 100644 (file)
index 0000000..714540a
--- /dev/null
@@ -0,0 +1,4 @@
+int foo(void)
+{
+  return 1;
+}
diff --git a/unit-tests/test-cases/reexport_symbols_list/foo.exp b/unit-tests/test-cases/reexport_symbols_list/foo.exp
new file mode 100644 (file)
index 0000000..70eefe9
--- /dev/null
@@ -0,0 +1 @@
+_foo
diff --git a/unit-tests/test-cases/reexport_symbols_list/junk.exp b/unit-tests/test-cases/reexport_symbols_list/junk.exp
new file mode 100644 (file)
index 0000000..8b925f7
--- /dev/null
@@ -0,0 +1 @@
+_junk
diff --git a/unit-tests/test-cases/reexport_symbols_list/main1.c b/unit-tests/test-cases/reexport_symbols_list/main1.c
new file mode 100644 (file)
index 0000000..4655cb6
--- /dev/null
@@ -0,0 +1,9 @@
+extern int foo();
+extern int bart();
+
+int main()
+{
+       foo();
+       bart();
+       return 0;
+}
index 4d38f2de3b9efaa2c93ef41302ccdc89bab09b89..86716dad291c3cfe856205aca4d5d37d37539d6d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2005-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -82,6 +82,9 @@ _test_branches:
        @ call internal + addend
        bne     _test_calls+16
 
+       @ call internal - addend
+       bne     _test_calls-16
+
        @ call external
        bne     _external
        
@@ -92,6 +95,35 @@ _test_branches:
        bl        1f
 1:     nop
 
+
+       .globl  _test_weak
+       .weak_definition _test_weak
+_test_weak:
+       nop
+       nop
+
+       .globl  _test_hidden_weak
+       .private_extern _test_hidden_weak
+       .weak_definition _test_hidden_weak
+_test_hidden_weak:
+       nop
+       nop
+
+
+_test_weak_call:
+       bl      _test_weak
+       bl      _test_weak+4
+
+
+_test_weak_hidden_pointer_call:
+       ldr             r12,L3
+       add             r12, pc, r12
+       nop
+       bx              r12
+L101:  
+       .long   _test_hidden_weak - L101 
+       
+       
        .text
 _pointer_diffs:
        .long _foo-1b
@@ -101,6 +133,7 @@ _pointer_diffs:
        .long (_test_branches - _test_loads) + -2097152
        .long (_test_calls - _test_loads) + -2097152 
 
+
        .text
        .code 32
 _arm1: 
@@ -178,8 +211,8 @@ L15:add     r3, pc
        .align 2
 L16:   .long   _thumb1-(L12+8)
 L17:   .long   _thumb2-(L13+8)
-L17a:  .long   _thumb3-(L3+8)
-L17b:  .long   _thumb4-(L3+8)
+L17a:  .long   _thumb3-(L13+8)
+L17b:  .long   _thumb4-(L13+8)
 L18:   .long   _arm1-(L14+8)
 L19:   .long   _arm2-(L15+8)
 L19a:  .long   _arm3-(L15+8)
@@ -192,6 +225,81 @@ _myVTable:
                .long   _thumb3
                .long   _arm1
                .long   _arm2
+
+#if __ARM_ARCH_7A__
+       .text
+               .align 2
+_arm16tests:
+       movw    r0, :lower16:_datahilo16
+       movt    r0, :upper16:_datahilo16
+       movw    r0, :lower16:_datahilo16+4
+       movt    r0, :upper16:_datahilo16+4
+       movw    r0, :lower16:_datahilo16alt
+       movt    r0, :upper16:_datahilo16alt
+       movw    r0, :lower16:_datahilo16alt+61440
+       movt    r0, :upper16:_datahilo16alt+61440
+       movw    r0, :lower16:_datahilo16alt+2048
+       movt    r0, :upper16:_datahilo16alt+2048
+       movw    r0, :lower16:_datahilo16alt+1792
+       movt    r0, :upper16:_datahilo16alt+1792
+       movw    r0, :lower16:_datahilo16alt+165
+       movt    r0, :upper16:_datahilo16alt+165
+Lpicbase:
+       movw    r0, :lower16:_datahilo16 - Lpicbase
+       movt    r0, :upper16:_datahilo16 - Lpicbase
+       movw    r0, :lower16:_datahilo16+4 - Lpicbase
+       movt    r0, :upper16:_datahilo16+4 - Lpicbase
+       movw    r0, :lower16:_datahilo16alt - Lpicbase
+       movt    r0, :upper16:_datahilo16alt - Lpicbase
+       movw    r0, :lower16:_datahilo16alt+61440 - Lpicbase
+       movt    r0, :upper16:_datahilo16alt+61440 - Lpicbase
+       movw    r0, :lower16:_datahilo16alt+2048 - Lpicbase
+       movt    r0, :upper16:_datahilo16alt+2048 - Lpicbase
+       movw    r0, :lower16:_datahilo16alt+1792 - Lpicbase
+       movt    r0, :upper16:_datahilo16alt+1792 - Lpicbase
+       movw    r0, :lower16:_datahilo16alt+165 - Lpicbase
+       movt    r0, :upper16:_datahilo16alt+165 - Lpicbase
+       bx      lr
+          
+       .code 16
+       .thumb_func _thumb16tests
+_thumb16tests:
+       movw    r0, :lower16:_datahilo16
+       movt    r0, :upper16:_datahilo16
+       movw    r0, :lower16:_datahilo16+4
+       movt    r0, :upper16:_datahilo16+4
+       movw    r0, :lower16:_datahilo16alt
+       movt    r0, :upper16:_datahilo16alt
+       movw    r0, :lower16:_datahilo16alt+61440
+       movt    r0, :upper16:_datahilo16alt+61440
+       movw    r0, :lower16:_datahilo16alt+2048
+       movt    r0, :upper16:_datahilo16alt+2048
+       movw    r0, :lower16:_datahilo16alt+1792
+       movt    r0, :upper16:_datahilo16alt+1792
+       movw    r0, :lower16:_datahilo16alt+165
+       movt    r0, :upper16:_datahilo16alt+165
+Lpicbase2:
+       movw    r0, :lower16:_datahilo16 - Lpicbase2
+       movt    r0, :upper16:_datahilo16 - Lpicbase2
+       movw    r0, :lower16:_datahilo16+4 - Lpicbase2
+       movt    r0, :upper16:_datahilo16+4 - Lpicbase2
+       movw    r0, :lower16:_datahilo16alt - Lpicbase2
+       movt    r0, :upper16:_datahilo16alt - Lpicbase2
+       movw    r0, :lower16:_datahilo16alt+61440 - Lpicbase2
+       movt    r0, :upper16:_datahilo16alt+61440 - Lpicbase2
+       movw    r0, :lower16:_datahilo16alt+2048 - Lpicbase2
+       movt    r0, :upper16:_datahilo16alt+2048 - Lpicbase2
+       movw    r0, :lower16:_datahilo16alt+1792 - Lpicbase2
+       movt    r0, :upper16:_datahilo16alt+1792 - Lpicbase2
+       movw    r0, :lower16:_datahilo16alt+165 - Lpicbase2
+       movt    r0, :upper16:_datahilo16alt+165 - Lpicbase2
+       bx      lr
+          
+       .data
+_datahilo16:   .long 0
+_datahilo16alt:        .long 0
+
+#endif
        
 #endif
 
@@ -309,6 +417,17 @@ _test_branches:
        
        ; call external + addend
        bne     _external+16
+
+       .globl  _test_weak
+       .weak_definition _test_weak
+_test_weak:
+       nop
+       nop
+       
+_test_weak_call:
+       bl      _test_weak
+       bl      _test_weak+4
+
 #endif
 
 
@@ -316,7 +435,12 @@ _test_branches:
 #if __i386__
        .text
        .align 2
-       
+
+Ltest_data:
+       .long   1
+       .long   2
+       .long   3
+
        .globl _test_loads
 _test_loads:
        pushl   %ebp
@@ -347,6 +471,10 @@ Lpicbase:
        # absolute lea of external + addend
        leal    _ax+0x1900, %eax
 
+       # absolute load of _test_data with negative addend and local label
+       movl    Ltest_data-16(%edi),%eax
+       movq    Ltest_data-16(%edi),%mm4
+       
        ret
 
 
@@ -406,6 +534,16 @@ c_2:
     sub          $(1), %ecx
     jcxz         c_2
 
+       .globl  _test_weak
+       .weak_definition _test_weak
+_test_weak:
+       nop
+       nop
+
+_test_weak_call:
+       call    _test_weak
+       call    _test_weak+1
+       
 #endif
 
 
@@ -483,19 +621,30 @@ _test_branches:
        jne     _external+16
        
 _byte_relocs:
+       # nonsense loop that creates byte branch relocation
     mov          $100, %ecx 
-c_1:  
+c_1:
     loop         _byte_relocs
     nop
 
+       .globl  _test_weak
+       .weak_definition _test_weak
+_test_weak:
+       nop
+       nop
+
+_test_weak_call:
+       call    _test_weak
+       call    _test_weak+1
+
 #endif
 
 
 
        # test that pointer-diff relocs are preserved
        .text
-_test_diffs:
        .align 2
+_test_diffs:
 Llocal2:
        .long 0
        .long Llocal2-_test_branches
@@ -511,6 +660,7 @@ Llocal2:
 #endif
 
 _foo: nop
+Lfoo: nop
 
        .align 2        
 _distance_from_foo:
@@ -528,6 +678,10 @@ _distance_to_here:
        .long   _foo - _distance_to_here
        .long   _foo - _distance_to_here - 4 
        .long   _foo - _distance_to_here - 12 
+       .long   Lfoo - _distance_to_here
+Ltohere:
+       .long   Lfoo - Ltohere
+       .long   Lfoo - Ltohere - 4
        .long   0
 
 
@@ -545,6 +699,7 @@ L1: .quad _test_branches - _test_diffs
        .quad _test_branches - .
        .quad _test_branches - L1
        .quad L1 - _prev                        
+       .quad _prev+100 - _test_branches
  #tests support for 32-bit absolute pointers
        .long _prev
        .long L1
@@ -570,11 +725,15 @@ _b:
        .long   _test_calls+16
        .long   _external
        .long   _external+16
+       .long   _test_weak
+       .long   _test_weak+16
 #elif __ppc64__ || __x86_64__
        .quad   _test_calls
        .quad   _test_calls+16
        .quad   _external
        .quad   _external+16
+       .quad   _test_weak
+       .quad   _test_weak+16
 #endif
 
        # test that reloc sizes are the same
index 36fb47b98dbc89b82e68c2128950fbd147b035d6..d4844584ee8023648fc662a526540bebdd07a82a 100644 (file)
@@ -1,5 +1,5 @@
 ##
-# Copyright (c) 2009 Apple Inc. All rights reserved.
+# Copyright (c) 2009-2010 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
@@ -41,10 +41,10 @@ run-other:
 
 run-i386:
        ${CC} ${ASMFLAGS} test.s -c -o test.o
-       ${OBJECTDUMP} test.o | grep "__data@0 plus 0xFFFFFFE2" | ${FAIL_IF_EMPTY}
+       ${OBJECTDUMP} test.o | grep "direct(anon@__data+0x00000000) + 0xFFFFFFFFFFFFFFE2" | ${FAIL_IF_EMPTY}
 
        ${LD} -arch ${ARCH} -r -keep_private_externs test.o -o test-r.o
-       ${OBJECTDUMP} test-r.o | grep "__data@0 plus 0xFFFFFFE2" | ${PASS_IFF_STDIN}
+       ${OBJECTDUMP} test-r.o | grep "direct(anon@__data+0x00000000) + 0xFFFFFFFFFFFFFFE2" | ${PASS_IFF_STDIN}
 
        
 clean:
diff --git a/unit-tests/test-cases/sectcreate-dead_strip/Makefile b/unit-tests/test-cases/sectcreate-dead_strip/Makefile
new file mode 100644 (file)
index 0000000..5b1f246
--- /dev/null
@@ -0,0 +1,40 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is a sanity check that ld
+# can link a hello-world program with no errors (or crashes)
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} main.c -o main -sectcreate __MYSEG __mysect sect_content -dead_strip
+       size -l main | grep __MYSEG | ${FAIL_IF_EMPTY}
+       size -l main | grep __mysect | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+       rm -f main
diff --git a/unit-tests/test-cases/sectcreate-dead_strip/main.c b/unit-tests/test-cases/sectcreate-dead_strip/main.c
new file mode 100644 (file)
index 0000000..fc047f7
--- /dev/null
@@ -0,0 +1,5 @@
+
+int main()
+{
+       return 0;
+}
diff --git a/unit-tests/test-cases/sectcreate-dead_strip/sect_content b/unit-tests/test-cases/sectcreate-dead_strip/sect_content
new file mode 100644 (file)
index 0000000..ce01362
--- /dev/null
@@ -0,0 +1 @@
+hello
diff --git a/unit-tests/test-cases/segment-labels/Makefile b/unit-tests/test-cases/segment-labels/Makefile
new file mode 100644 (file)
index 0000000..2a4a95b
--- /dev/null
@@ -0,0 +1,40 @@
+##
+# Copyright (c) 2009-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 ld resolves the magic segment start/end symbols.
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} main.c -dynamiclib -o libmain.dylib 
+       ${CC} ${CCFLAGS} main.c -o main 
+       ${CC} ${CCFLAGS} test.c -o test.preload -Wl,-preload -nostartfiles -nodefaultlibs -e _start
+       ${CC} ${CCFLAGS} test.c -o test.preload-pie -Wl,-preload -Wl,-pie -nostartfiles -nodefaultlibs -e _start
+       ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+       rm -f libmain.dylib main test.preload test.preload-pie
diff --git a/unit-tests/test-cases/segment-labels/main.c b/unit-tests/test-cases/segment-labels/main.c
new file mode 100644 (file)
index 0000000..441860f
--- /dev/null
@@ -0,0 +1,50 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2009-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+
+extern void* data_start  __asm("segment$start$__DATA");
+extern void* data_end    __asm("segment$end$__DATA");
+extern void* text_start  __asm("segment$start$__TEXT");
+extern void* text_end    __asm("segment$end$__TEXT");
+extern void* other_start __asm("segment$start$__OTHER");
+extern void* other_end   __asm("segment$end$__OTHER");
+
+
+int other[100] __attribute__ ((section ("__OTHER,__my"))) = { 1, 2 };
+
+int mytent[1000];
+static int mybss[1000];
+
+int main()
+{
+       mytent[0] = 0;
+       mybss[0] = 0;
+       printf("text %p -> %p\n", &text_start, &text_end);
+       printf("data %p -> %p\n", &data_start, &data_end);
+       printf("other %p -> %p\n", &other_start, &other_end);
+       return 0;
+}
+
+
diff --git a/unit-tests/test-cases/segment-labels/test.c b/unit-tests/test-cases/segment-labels/test.c
new file mode 100644 (file)
index 0000000..247b989
--- /dev/null
@@ -0,0 +1,12 @@
+extern char text_start[] __asm("segment$start$__TEXT");
+extern char text_end[] __asm("segment$end$__TEXT");
+extern char text_text_start[] __asm("section$start$__TEXT$__text");
+
+void* a = &text_start;
+void* b = &text_end;
+void* c = &text_text_start;
+
+void start(void)
+{
+}
+
index 6e11c596a2bbc69478ec7b7059731f3817ea505d..806f40666348b1536db02cf05cae01217fcb17ce 100644 (file)
@@ -34,18 +34,18 @@ include ${TESTROOT}/include/common.makefile
 run: all
 
 all: hello.o other.o 
-       ${CXX} ${CCXXFLAGS} -gstabs+ -gused hello.o other.o -o stabs-hello-${ARCH}
+       g++-4.2 ${CCXXFLAGS} -gstabs+ -gused hello.o other.o -o stabs-hello-${ARCH}
        ${FAIL_IF_BAD_MACHO} stabs-hello-${ARCH}
        nm -ap stabs-hello-${ARCH} | grep FUN | grep _Z3fooi | wc -l > stabs-hello-foo-count
        echo "       1" > one
        ${PASS_IFF} diff stabs-hello-foo-count one
 
 hello.o : hello.cxx
-       ${CXX} ${CCXXFLAGS} -gstabs+ -gused hello.cxx -c -o $@
+       g++-4.2 ${CCXXFLAGS} -gstabs+ -gused hello.cxx -c -o $@
        ${FAIL_IF_BAD_OBJ} $@
 
 other.o : other.cxx
-       ${CXX} ${CCXXFLAGS} -gstabs+ -gused other.cxx -c -o $@
+       g++-4.2 ${CCXXFLAGS} -gstabs+ -gused other.cxx -c -o $@
        ${FAIL_IF_BAD_OBJ} $@
 
 clean:
index 05588b573ef800662dafc817cee2b4529d92094b..4e61937a0e79a4101093cdab1668e03668396f20 100644 (file)
@@ -29,7 +29,8 @@ include ${TESTROOT}/include/common.makefile
 
 all:
        ${CC} ${CCFLAGS} test.c -static -o test -e _entry -nostdlib -Wl,-new_linker
+       strip -S test -o test.stripped
        ${PASS_IFF_GOOD_MACHO} test
 
 clean:
-       rm -rf test
+       rm -rf test  test.stripped
index 3e03861e59859f6c873883a55c66950c1e26501b..687cb3d315bac68b286aabdcaaffc6271e96b0f0 100644 (file)
@@ -11,3 +11,6 @@ int entry()
 {
        return foo();
 }
+
+// pointer to weak function might trigger external relocation
+void* pfoo = &foo;
index 27fe88d66b1c5c2ce0758644de85abb9fb9ac758..57b349af1d7813c195882f958d97041f430579a4 100644 (file)
@@ -1,7 +1,10 @@
 
+int a;
+int b = 5;
+
 int foo()
 {
-       return 0;
+       return a+b;
 }
 
 
@@ -9,3 +12,5 @@ int entry()
 {
        return foo();
 }
+
+
diff --git a/unit-tests/test-cases/symbol-hiding-umbrella/Makefile b/unit-tests/test-cases/symbol-hiding-umbrella/Makefile
new file mode 100644 (file)
index 0000000..3fc3aa0
--- /dev/null
@@ -0,0 +1,48 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test magic $ld$hide works with public sub library
+# <rdar://problem/8388362> RedGarnet's linker does not honor $ld$hide for umbrella libraries
+#
+
+
+run: all
+
+all:
+       # In this test case aaa and bbb both moved between libfoo and libar
+       # between 10.4 and 10.5.
+       ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib -install_name /usr/lib/libbar.dylib
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -Wl,-reexport_library,libbar.dylib -o libfoo.dylib 
+       ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib -install_name /usr/lib/libbar_alt.dylib
+       ${CC} ${CCFLAGS} main.c -o main-10.5  libfoo.dylib -L. -mmacosx-version-min=10.5
+       ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} main.c -o main-10.6  libfoo.dylib -L. -mmacosx-version-min=10.6  2>/dev/null
+       ${CC} ${CCFLAGS} main.c -o main-10.7  libfoo.dylib -L. -mmacosx-version-min=10.7
+       ${PASS_IFF_GOOD_MACHO} main-10.7
+
+
+clean:
+
+       rm -rf  libbar.dylib libfoo.dylib main-10.5 main-10.6 main-10.7
diff --git a/unit-tests/test-cases/symbol-hiding-umbrella/bar.c b/unit-tests/test-cases/symbol-hiding-umbrella/bar.c
new file mode 100644 (file)
index 0000000..e425999
--- /dev/null
@@ -0,0 +1 @@
+void bar() {}
diff --git a/unit-tests/test-cases/symbol-hiding-umbrella/foo.c b/unit-tests/test-cases/symbol-hiding-umbrella/foo.c
new file mode 100644 (file)
index 0000000..d946cb4
--- /dev/null
@@ -0,0 +1,7 @@
+
+void foo() {}
+
+#define SYMBOL_NOT_HERE_IN_10_6(sym) \
+                 extern const char sym##_tmp __asm("$ld$hide$os10.6$_" #sym ); const char sym##_tmp = 0;
+                               
+SYMBOL_NOT_HERE_IN_10_6(bar)
diff --git a/unit-tests/test-cases/symbol-hiding-umbrella/main.c b/unit-tests/test-cases/symbol-hiding-umbrella/main.c
new file mode 100644 (file)
index 0000000..8c9c95c
--- /dev/null
@@ -0,0 +1,11 @@
+
+extern void foo();
+extern void bar();
+
+
+int main()
+{
+       foo();
+       bar();
+       return 0;
+}
diff --git a/unit-tests/test-cases/symbol-resolver-basic/Makefile b/unit-tests/test-cases/symbol-resolver-basic/Makefile
new file mode 100644 (file)
index 0000000..15cb555
--- /dev/null
@@ -0,0 +1,29 @@
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test a simple symbol resolver function
+#
+TARGET = all
+ifeq (${ARCH},ppc)
+       TARGET = all-ppc
+endif
+
+
+run: ${TARGET}
+
+all:
+       ${CC} ${CCFLAGS} foo.c -c -o foo.o
+       ${CC} ${CCFLAGS} foo.o -dynamiclib -o libfoo.dylib 
+       ${DYLDINFO} -export libfoo.dylib | grep _foo | grep resolver | ${FAIL_IF_EMPTY}
+       ${LD} -arch ${ARCH} -r foo.o -o foo-r.o
+       ${CC} ${CCFLAGS} foo-r.o -dynamiclib -o libfoo-r.dylib 
+       ${DYLDINFO} -export libfoo-r.dylib | grep _foo | grep resolver | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} libfoo-r.dylib
+
+all-ppc:
+       echo "PASS"
+
+clean:
+       rm  -f foo.o  libfoo.dylib foo-r.o libfoo-r.dylib
diff --git a/unit-tests/test-cases/symbol-resolver-basic/foo.c b/unit-tests/test-cases/symbol-resolver-basic/foo.c
new file mode 100644 (file)
index 0000000..c6a39d9
--- /dev/null
@@ -0,0 +1,38 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+
+int foo_real()
+{
+       return 10;
+}
+
+// This foo is a "resolver" function that return the actual address of "foo"
+void* foo()
+{
+       __asm__(".desc _foo, 0x100");
+       return &foo_real;
+}
+
diff --git a/unit-tests/test-cases/symbol-resolver-hidden/Makefile b/unit-tests/test-cases/symbol-resolver-hidden/Makefile
new file mode 100644 (file)
index 0000000..754dad4
--- /dev/null
@@ -0,0 +1,25 @@
+
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test a simple symbol resolver function
+#
+TARGET = all
+ifeq (${ARCH},ppc)
+       TARGET = all-ppc
+endif
+
+
+run: ${TARGET}
+
+all:
+       ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib -Wl,-w
+       ${DYLDINFO} -lazy_bind libfoo.dylib | grep _a | ${FAIL_IF_STDIN}
+       ${PASS_IFF_GOOD_MACHO} libfoo.dylib
+
+all-ppc:
+       echo "PASS"
+
+clean:
+       rm  -f  libfoo.dylib 
diff --git a/unit-tests/test-cases/symbol-resolver-hidden/foo.c b/unit-tests/test-cases/symbol-resolver-hidden/foo.c
new file mode 100644 (file)
index 0000000..c8e29e3
--- /dev/null
@@ -0,0 +1,42 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <stdio.h>
+
+extern void a();
+
+void b() {
+       a();
+}
+
+static void a_impl() {
+       printf("Hello World!\n");
+}
+
+void *a_chooser() __asm__("_a") __attribute__((visibility("hidden"), noinline));
+void *a_chooser() {
+       __asm__(".symbol_resolver _a");
+       return a_impl;
+}
+
index df0ae07def371435ec34bbd6814d6dc5384780ab..6a7d3a6d091fd87bd5943ea71ffdfe00f4d004b7 100644 (file)
@@ -32,10 +32,10 @@ run: all
 
 all:
        ${CC} ${CCFLAGS} test.c -c -o test.${ARCH}.o
-       ${OBJECTDUMP} -no_content test.${ARCH}.o | grep -v kind: | grep -v section: > test.${ARCH}.o.dump
+       ${OBJECTDUMP} -no_content -no_definition -no_section -no_combine test.${ARCH}.o  > test.${ARCH}.o.dump
 
        ${LD} -arch ${ARCH} -r -d test.${ARCH}.o -o test-r-d.${ARCH}.o
-       ${OBJECTDUMP} -no_content test-r-d.${ARCH}.o | grep -v kind: | grep -v section: > test-r-d.${ARCH}.o.dump
+       ${OBJECTDUMP} -no_content -no_definition -no_section -no_combine test-r-d.${ARCH}.o > test-r-d.${ARCH}.o.dump
        
        ${PASS_IFF} diff test.${ARCH}.o.dump  test-r-d.${ARCH}.o.dump
        
diff --git a/unit-tests/test-cases/tlv-basic/Makefile b/unit-tests/test-cases/tlv-basic/Makefile
new file mode 100644 (file)
index 0000000..f5be591
--- /dev/null
@@ -0,0 +1,39 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that main executable can use TLVs
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} main.c get.s -o main
+       otool -lv main | grep S_THREAD_LOCAL_VARIABLES | ${FAIL_IF_EMPTY}
+       otool -lv main | grep S_THREAD_LOCAL_REGULAR | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+       rm  main
diff --git a/unit-tests/test-cases/tlv-basic/get.s b/unit-tests/test-cases/tlv-basic/get.s
new file mode 100644 (file)
index 0000000..9255841
--- /dev/null
@@ -0,0 +1,162 @@
+
+               # _a is zerofill global TLV
+               .tbss _a$tlv$init,4,2
+
+               # _b is an initialized global TLV
+               .tdata
+_b$tlv$init:    
+               .long   5
+
+                # _c is zerofill non-external TLV
+               .tbss _c$tlv$init,4,2
+
+               # _d is an initialized non-external TLV
+               .tdata
+_d$tlv$init:   
+               .long   5
+
+#if __x86_64__
+
+               # _a is global TLV
+               .tlv
+               .globl _a
+_a:            .quad   __tlv_bootstrap
+               .quad   0
+               .quad   _a$tlv$init
+
+               # _b is a global TLV
+               .tlv
+               .globl _b
+_b:            .quad   __tlv_bootstrap
+               .quad   0
+               .quad   _b$tlv$init
+
+               # _c is a non-external TLV
+               .tlv
+_c:            .quad   __tlv_bootstrap
+               .quad   0
+               .quad   _c$tlv$init
+
+               # _d is a non-external TLV
+               .tlv
+_d:            .quad   __tlv_bootstrap
+               .quad   0
+               .quad   _d$tlv$init
+
+
+       .text
+       .globl  _get_a
+_get_a:
+       pushq   %rbp
+       movq    %rsp, %rbp
+       movq    _a@TLVP(%rip), %rdi
+       call    *(%rdi)
+       popq    %rbp
+       ret
+
+       .globl  _get_b
+_get_b:
+       pushq   %rbp
+       movq    %rsp, %rbp
+       movq    _b@TLVP(%rip), %rdi
+       call    *(%rdi)
+       popq    %rbp
+       ret
+       
+       .globl  _get_c
+_get_c:
+       pushq   %rbp
+       movq    %rsp, %rbp
+       movq    _c@TLVP(%rip), %rdi
+       call    *(%rdi)
+       popq    %rbp
+       ret
+
+       .globl  _get_d
+_get_d:
+       pushq   %rbp
+       movq    %rsp, %rbp
+       movq    _d@TLVP(%rip), %rdi
+       call    *(%rdi)
+       popq    %rbp
+       ret
+
+#endif
+
+#if __i386__
+
+               # _a is global TLV
+               .tlv
+               .globl _a
+_a:            .long   __tlv_bootstrap
+               .long   0
+               .long   _a$tlv$init
+
+               # _b is a global TLV
+               .tlv
+               .globl _b
+_b:            .long   __tlv_bootstrap
+               .long   0
+               .long   _b$tlv$init
+
+               # _c is a non-external TLV
+               .tlv
+_c:            .long   __tlv_bootstrap
+               .long   0
+               .long   _c$tlv$init
+
+               # _d is a non-external TLV
+               .tlv
+_d:            .long   __tlv_bootstrap
+               .long   0
+               .long   _d$tlv$init
+
+
+       .text
+       .globl  _get_a
+_get_a:
+       pushl   %ebp
+       movl    %esp, %ebp
+       subl    $8, %esp
+       movl    _a@TLVP, %eax
+       call    *(%eax)    
+       movl    %ebp, %esp
+       popl    %ebp
+       ret
+
+       .globl  _get_b
+_get_b:
+       pushl   %ebp
+       movl    %esp, %ebp
+       subl    $8, %esp
+       movl    _b@TLVP, %eax
+       call    *(%eax)    
+       movl    %ebp, %esp
+       popl    %ebp
+       ret
+
+       .globl  _get_c
+_get_c:
+       pushl   %ebp
+       movl    %esp, %ebp
+       subl    $8, %esp
+       movl    _c@TLVP, %eax
+       call    *(%eax)    
+       movl    %ebp, %esp
+       popl    %ebp
+       ret
+
+       .globl  _get_d
+_get_d:
+       pushl   %ebp
+       movl    %esp, %ebp
+       subl    $8, %esp
+       movl    _d@TLVP, %eax
+       call    *(%eax)    
+       movl    %ebp, %esp
+       popl    %ebp
+       ret
+
+#endif
+
+.subsections_via_symbols
diff --git a/unit-tests/test-cases/tlv-basic/main.c b/unit-tests/test-cases/tlv-basic/main.c
new file mode 100644 (file)
index 0000000..fc56a13
--- /dev/null
@@ -0,0 +1,39 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+// work around until compiler supports __thread
+extern int* get_a();           
+extern int* get_b();
+extern int* get_c();   
+extern int* get_d();   
+
+int main()
+{
+       get_a();
+       get_b();
+       get_c();
+       get_d();
+       return 0;
+}
+
diff --git a/unit-tests/test-cases/tlv-dylib/Makefile b/unit-tests/test-cases/tlv-dylib/Makefile
new file mode 100644 (file)
index 0000000..5017692
--- /dev/null
@@ -0,0 +1,46 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+#
+# Check that dylibs can export TLVs
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} foo.s -dynamiclib -o libfoo.dylib
+       # check trying to access TLV _foo as regular variable is an error
+       ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} main.c -DUSE_FOO libfoo.dylib -o main 2>/dev/null
+       # check trying to access regular variable _bar as TLV is an error
+       ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} main.c getbar.s libfoo.dylib -o main 2>/dev/null
+       # check can link with TLV _foo in dylib
+       ${CC} ${CCFLAGS} main.c getfoo.s libfoo.dylib -o main
+       ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+       rm -rf libfoo.dylib main
diff --git a/unit-tests/test-cases/tlv-dylib/foo.s b/unit-tests/test-cases/tlv-dylib/foo.s
new file mode 100644 (file)
index 0000000..fd2f23d
--- /dev/null
@@ -0,0 +1,33 @@
+
+// _foo is an exported thread local variable
+// _bar is an exported regular variable
+
+               # _a is zerofill global TLV
+               .tbss _a$tlv$init,4,2
+
+#if __x86_64__
+               .tlv
+               .globl _foo
+_foo:  .quad   __tlv_bootstrap
+               .quad   0
+               .quad   _a$tlv$init
+
+
+#endif
+
+#if __i386__
+               .tlv
+               .globl _foo
+_foo:  .long   __tlv_bootstrap
+               .long   0
+               .long   _a$tlv$init
+#endif
+
+
+               .data
+               .globl _bar
+_bar:  .long   0
+
+
+
+               .subsections_via_symbols
diff --git a/unit-tests/test-cases/tlv-dylib/getbar.s b/unit-tests/test-cases/tlv-dylib/getbar.s
new file mode 100644 (file)
index 0000000..33b0418
--- /dev/null
@@ -0,0 +1,29 @@
+
+#if __x86_64__
+       .text
+       .globl  _get_bar
+_get_bar:
+       pushq   %rbp
+       movq    %rsp, %rbp
+       movq    _bar@TLVP(%rip), %rdi
+       call    *(%rdi)
+       popq    %rbp
+       ret
+#endif
+
+
+#if __i386__
+       .text
+       .globl  _get_bar
+_get_bar:
+       pushl   %ebp
+       movl    %esp, %ebp
+       subl    $8, %esp
+       movl    _bar@TLVP, %eax
+       call    *(%eax)    
+       movl    %ebp, %esp
+       popl    %ebp
+       ret
+#endif
+
+.subsections_via_symbols
diff --git a/unit-tests/test-cases/tlv-dylib/getfoo.s b/unit-tests/test-cases/tlv-dylib/getfoo.s
new file mode 100644 (file)
index 0000000..21db32c
--- /dev/null
@@ -0,0 +1,29 @@
+
+#if __x86_64__
+       .text
+       .globl  _get_foo
+_get_foo:
+       pushq   %rbp
+       movq    %rsp, %rbp
+       movq    _foo@TLVP(%rip), %rdi
+       call    *(%rdi)
+       popq    %rbp
+       ret
+#endif
+
+
+#if __i386__
+       .text
+       .globl  _get_foo
+_get_foo:
+       pushl   %ebp
+       movl    %esp, %ebp
+       subl    $8, %esp
+       movl    _foo@TLVP, %eax
+       call    *(%eax)    
+       movl    %ebp, %esp
+       popl    %ebp
+       ret
+#endif
+
+.subsections_via_symbols
diff --git a/unit-tests/test-cases/tlv-dylib/main.c b/unit-tests/test-cases/tlv-dylib/main.c
new file mode 100644 (file)
index 0000000..d5ec3b8
--- /dev/null
@@ -0,0 +1,36 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#if USE_FOO
+       extern int foo;
+#endif
+
+int main()
+{
+#if USE_FOO
+       foo = 1;
+#endif
+       return 0;
+}
+
diff --git a/unit-tests/test-cases/umbrella-dylib/Makefile b/unit-tests/test-cases/umbrella-dylib/Makefile
new file mode 100644 (file)
index 0000000..b20f368
--- /dev/null
@@ -0,0 +1,54 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test out building an umbrella dylib.  a and c are co-dependent.  b depends on c.
+#
+
+
+run: all
+
+all:
+       # build bootstrap dylib of with all code
+       ${CC} ${CCFLAGS} -dynamiclib a.c b.c c.c -o libBig.stub  -install_name /usr/lib/libBig.dylib 
+       # link each sub library against bootstrap to intra-Big symbols
+       ${CC} ${CCFLAGS} -dynamiclib a.c -o liba.dylib libBig.stub -install_name /usr/local/lib/big/liba.dylib -umbrella Big
+       ${CC} ${CCFLAGS} -dynamiclib b.c -o libb.dylib libBig.stub -install_name /usr/local/lib/big/libb.dylib -umbrella Big
+       ${CC} ${CCFLAGS} -dynamiclib c.c -o libc.dylib libBig.stub -install_name /usr/local/lib/big/libc.dylib -umbrella Big
+       ${CC} ${CCFLAGS} -dynamiclib -Wl,-reexport_library,liba.dylib -Wl,-reexport_library,libb.dylib -Wl,-reexport_library,libc.dylib -o libBig.dylib -install_name /usr/lib/libBig.dylib 
+       # re-link against correct dylibs now that everything is built
+       ${CC} ${CCFLAGS} -dynamiclib a.c -o liba.dylib libc.dylib -install_name /usr/local/lib/big/liba.dylib -umbrella Big
+       dyldinfo -lazy_bind liba.dylib | grep c2 | grep libc | ${FAIL_IF_EMPTY}
+       ${CC} ${CCFLAGS} -dynamiclib b.c -o libb.dylib libc.dylib -install_name /usr/local/lib/big/libb.dylib -umbrella Big
+       ${CC} ${CCFLAGS} -dynamiclib c.c -o libc.dylib liba.dylib -install_name /usr/local/lib/big/libc.dylib -umbrella Big
+       dyldinfo -lazy_bind libc.dylib | grep a2 | grep liba | ${FAIL_IF_EMPTY}
+       ${CC} ${CCFLAGS} -dynamiclib -Wl,-reexport_library,liba.dylib -Wl,-reexport_library,libb.dylib -Wl,-reexport_library,libc.dylib -o libBig.dylib -install_name /usr/lib/libBig.dylib 
+       ${CC} ${CCFLAGS} main.c -o main libBig.dylib -L.
+       ${PASS_IFF_GOOD_MACHO} main
+
+
+clean:
+
+       rm -rf libBig.stub liba.dylib libb.dylib libc.dylib libBig.dylib main
diff --git a/unit-tests/test-cases/umbrella-dylib/a.c b/unit-tests/test-cases/umbrella-dylib/a.c
new file mode 100644 (file)
index 0000000..83ff3fc
--- /dev/null
@@ -0,0 +1,11 @@
+
+extern void c2();
+
+void a1(void)
+{
+       c2();
+}
+
+void a2(void)
+{
+}
diff --git a/unit-tests/test-cases/umbrella-dylib/b.c b/unit-tests/test-cases/umbrella-dylib/b.c
new file mode 100644 (file)
index 0000000..cdb9dfa
--- /dev/null
@@ -0,0 +1,7 @@
+
+extern void c1();
+
+void b1(void)
+{
+       c1();
+}
diff --git a/unit-tests/test-cases/umbrella-dylib/c.c b/unit-tests/test-cases/umbrella-dylib/c.c
new file mode 100644 (file)
index 0000000..01747b6
--- /dev/null
@@ -0,0 +1,11 @@
+
+extern void a2();
+
+void c1(void)
+{
+       a2();
+}
+
+void c2(void)
+{
+}
diff --git a/unit-tests/test-cases/umbrella-dylib/main.c b/unit-tests/test-cases/umbrella-dylib/main.c
new file mode 100644 (file)
index 0000000..8d0b5b7
--- /dev/null
@@ -0,0 +1,8 @@
+extern void c1();
+extern void a1();
+int main()
+{
+  a1();
+  c1();
+  return 0;
+}
index eebcc37909a5af217a6cc44dea9c310ed739f530..69b40c7f4a062ce9ec2bf88d9afbc95198a664c0 100644 (file)
@@ -1,5 +1,5 @@
 ##
-# Copyright (c) 2007 Apple Inc. All rights reserved.
+# Copyright (c) 2007-2010 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
@@ -30,18 +30,31 @@ include ${TESTROOT}/include/common.makefile
 run: all
 
 all:
-       ${CC} ${CCFLAGS} main.c -o main -undefined dynamic_lookup 
+       ${CC} ${CCFLAGS} main.c -o main -undefined dynamic_lookup
        nm -m main | grep _foo | grep "dynamically looked up" | ${FAIL_IF_EMPTY}
+       ${DYLDINFO} -lazy_bind -bind main | grep _foo | grep "flat-namespace" | ${FAIL_IF_EMPTY}
+       ${DYLDINFO} -lazy_bind -bind main | grep _exit | grep "flat-namespace" | ${FAIL_IF_STDIN}
        ${FAIL_IF_BAD_MACHO} main
 
        ${CC} ${CCFLAGS} main.c -o main -Wl,-U,_foo 
        nm -m main | grep _foo | grep "dynamically looked up" | ${FAIL_IF_EMPTY}
+       ${DYLDINFO} -lazy_bind -bind main | grep _foo | grep "flat-namespace" | ${FAIL_IF_EMPTY}
+       ${DYLDINFO} -lazy_bind -bind main | grep _exit | grep "flat-namespace" | ${FAIL_IF_STDIN}
        ${FAIL_IF_BAD_MACHO} main
 
        ${CC} ${CCFLAGS} main.c -o main -flat_namespace -Wl,-U,_foo
        nm -m main | grep _foo | grep "dynamically looked up" | ${FAIL_IF_STDIN}
-       ${PASS_IFF_GOOD_MACHO} main
+       ${DYLDINFO} -lazy_bind -bind main | grep _foo | grep "flat-namespace" | ${FAIL_IF_EMPTY}
+       ${DYLDINFO} -lazy_bind -bind main | grep _exit | grep "flat-namespace" | ${FAIL_IF_EMPTY}
+       ${FAIL_IF_BAD_MACHO} main
+
+       ${CC} ${CCFLAGS} main.c -bundle -o main.bundle -nodefaultlibs -undefined dynamic_lookup 
+       nm -m main.bundle | grep _foo | grep "dynamically looked up" | ${FAIL_IF_EMPTY}
+       ${DYLDINFO} -lazy_bind -bind main.bundle | grep _foo | grep "flat-namespace" | ${FAIL_IF_EMPTY}
+       ${DYLDINFO} -lazy_bind -bind main.bundle | grep _exit | grep "flat-namespace" | ${FAIL_IF_STDIN}
+       ${PASS_IFF_GOOD_MACHO} main.bundle
+
 
 
 clean:
-       rm  main
+       rm -f main main.bundle
diff --git a/unit-tests/test-cases/unstrippable-symbols/Makefile b/unit-tests/test-cases/unstrippable-symbols/Makefile
new file mode 100644 (file)
index 0000000..39937ba
--- /dev/null
@@ -0,0 +1,17 @@
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that a dynamically referenced symbol is always exported
+#
+
+run: all
+
+all:
+       ${CC} foo.c -dynamiclib -o libfoo.dylib
+       nm -m libfoo.dylib | grep _keep_global | grep "referenced dynamically" | ${FAIL_IF_EMPTY}
+       nm -m libfoo.dylib | grep _keep_hidden | grep "referenced dynamically" | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} libfoo.dylib
+
+clean:
+       rm  libfoo.dylib
diff --git a/unit-tests/test-cases/unstrippable-symbols/foo.c b/unit-tests/test-cases/unstrippable-symbols/foo.c
new file mode 100644 (file)
index 0000000..140f8c6
--- /dev/null
@@ -0,0 +1,24 @@
+#include <stddef.h>
+
+int  keep_global = 1;
+asm(".desc _keep_global, 0x10");
+
+__attribute__((visibility("hidden"))) int  keep_hidden = 1;
+asm(".desc _keep_hidden, 0x10");
+
+static int  keep_static = 1;
+asm(".desc _keep_static, 0x10");
+
+
+int  lose_global = 1;
+
+__attribute__((visibility("hidden"))) int  lose_hidden = 1;
+
+static int  lose_static = 1;
+
+
+
+int get()
+{
+       return keep_global + keep_hidden + keep_static + lose_global + lose_hidden + lose_static;
+}
diff --git a/unit-tests/test-cases/utf16-nul/Makefile b/unit-tests/test-cases/utf16-nul/Makefile
new file mode 100644 (file)
index 0000000..3d845e5
--- /dev/null
@@ -0,0 +1,41 @@
+##
+# Copyright (c) 2008-2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that utf16 cfstring literals are coalesced.
+# There is 3 CFSTR in foo.m and 1 CFSTR in bar.m
+# After coalescing and dead stripping there should be only two CFSTR in the output
+#
+
+
+all:
+       ${CC} ${CCFLAGS} withnul.s -c -o withnul.o
+       ${CC} ${CCFLAGS} other.s -c -o other.o
+       ${LD} -r -arch ${ARCH} withnul.o other.o -o all.o
+       size -l all.o | grep "__ustring): 44" | ${PASS_IFF_STDIN}
+       
+
+clean:
+       rm -rf withnul.o other.o all.o
diff --git a/unit-tests/test-cases/utf16-nul/other.s b/unit-tests/test-cases/utf16-nul/other.s
new file mode 100644 (file)
index 0000000..f78d014
--- /dev/null
@@ -0,0 +1,12 @@
+
+
+       .section        __TEXT,__ustring
+       .align  1
+___utf16_string_3:
+       .short  0x00fc, 0x0062, 0x0065, 0x0072, 0x0000
+       
+___utf16_string_4:
+       .short  0x0073, 0x0074, 0x00fc, 0x0066, 0x0066, 0x0000
+
+
+
diff --git a/unit-tests/test-cases/utf16-nul/withnul.s b/unit-tests/test-cases/utf16-nul/withnul.s
new file mode 100644 (file)
index 0000000..a1bc7ce
--- /dev/null
@@ -0,0 +1,8 @@
+
+
+       .section        __TEXT,__ustring
+       .align  1
+___utf16_string_1:
+       .short  0x00fc, 0x0062, 0x0065, 0x0072, 0x0000, 0x0073, 0x0074, 0x00fc, 0x0066, 0x0066, 0x0000
+
+
index 43bdcd8f187bf91f2fe06140a5a1203c8b6493da..64b03634fbd551eeca7845daded6d38732ff7832 100644 (file)
@@ -1,5 +1,5 @@
 ##
-# Copyright (c) 2007 Apple Inc. All rights reserved.
+# Copyright (c) 2007-2010 Apple Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
@@ -39,18 +39,24 @@ all:
        ${CC} ${CCFLAGS} -c foo_weak.c -o foo_weak.o
        ${CC} ${CCFLAGS} -c foo.c -o foo.o
        ${CC} ${CCFLAGS} -c foo_hidden.c -o foo_hidden.o
-       # weak default and weak hidden should warn
-       ${CC} ${CCFLAGS} foo_weak_hidden.o foo_weak.o -dynamiclib -o libfoo.dylib 2> warnings.log
-       grep visibility warnings.log | ${FAIL_IF_EMPTY}
-       # weak hidden and strong should not warn
-       ${CC} ${CCFLAGS} foo_weak_hidden.o foo.o -dynamiclib -o libfoo.dylib  2> warnings.log
-       grep visibility warnings.log | ${FAIL_IF_STDIN}
-       # weak default and strong hidden should not warn
-       ${CC} ${CCFLAGS} foo_weak.o foo_hidden.o -dynamiclib -o libfoo.dylib  2> warnings.log
-       grep visibility warnings.log | ${FAIL_IF_STDIN}
-       # weak default and weak hidden but -w should not warn
-       ${CC} ${CCFLAGS} foo_weak_hidden.o foo_weak.o -dynamiclib -w -o libfoo.dylib 2> warnings.log
-       cat warnings.log | ${FAIL_IF_STDIN}
+       # weak default and weak hidden should pick default
+       ${CC} ${CCFLAGS} foo_weak_hidden.o foo_weak.o -dynamiclib -o libfoo.dylib 
+       nm -m libfoo.dylib | grep _foo | grep "private external" | ${FAIL_IF_STDIN}
+       # weak default and weak hidden should pick default
+       ${CC} ${CCFLAGS} foo_weak.o foo_weak_hidden.o -dynamiclib -o libfoo.dylib 
+       nm -m libfoo.dylib | grep _foo | grep "private external" | ${FAIL_IF_STDIN}
+       # weak hidden and strong should not warn and pick strong
+       ${CC} ${CCFLAGS} foo_weak_hidden.o foo.o -dynamiclib -o libfoo.dylib  
+       nm -m libfoo.dylib | grep _foo | grep weak | ${FAIL_IF_STDIN}
+       nm -m libfoo.dylib | grep _foo | grep "private external" | ${FAIL_IF_STDIN}
+       # weak default and strong hidden should not warn and pick hidden
+       ${CC} ${CCFLAGS} foo_weak.o foo_hidden.o -dynamiclib -o libfoo.dylib 
+       nm -m libfoo.dylib | grep _foo | grep weak | ${FAIL_IF_STDIN}
+       nm -m libfoo.dylib | grep _foo | grep "private external" | ${FAIL_IF_EMPTY}
+       # weak default and strong hidden should not warn and pick hidden
+       ${CC} ${CCFLAGS} foo_hidden.o foo_weak.o  -dynamiclib -o libfoo.dylib 
+       nm -m libfoo.dylib | grep _foo | grep weak | ${FAIL_IF_STDIN}
+       nm -m libfoo.dylib | grep _foo | grep "private external" | ${FAIL_IF_EMPTY}
        ${PASS_IFF_GOOD_MACHO} libfoo.dylib
 
 clean:
diff --git a/unit-tests/test-cases/weak-def-auto-hide/Makefile b/unit-tests/test-cases/weak-def-auto-hide/Makefile
new file mode 100644 (file)
index 0000000..7b74b81
--- /dev/null
@@ -0,0 +1,57 @@
+##
+# Copyright (c) 2010Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, 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
+
+
+#
+# Tests weak-external and weak-can-be-hidden symbols work.
+#
+
+run: all
+
+all: 
+       # test that _my_other_weak is hidden
+       ${CC} ${CCFLAGS} main.c -c -o main.o
+       ${CC} ${CCFLAGS} other.s -c -o other.o
+       ${CC} ${CCFLAGS} main.o other.o -o main
+       nm -m main | grep _my_weak | grep "weak external" | ${FAIL_IF_EMPTY}
+       nm -m main | grep _my_other_weak | grep "non-external" | ${FAIL_IF_EMPTY}
+       ${FAIL_IF_BAD_MACHO} main
+       # test that .exp file can override auto-hide
+       ${CC} ${CCFLAGS} main.o other.o -o main2 -Wl,-exported_symbol,_my_other_weak
+       nm -m main2 | grep _my_weak | grep "non-external" | ${FAIL_IF_EMPTY}
+       nm -m main2 | grep _my_other_weak | grep "weak external" | ${FAIL_IF_EMPTY}
+       ${FAIL_IF_BAD_MACHO} main2
+       ${CC} ${CCFLAGS} main.o other.o -o main2 -Wl,-exported_symbol,_main
+       nm -m main2 | grep _my_weak | grep "non-external" | ${FAIL_IF_EMPTY}
+       nm -m main2 | grep _my_other_weak | grep "non-external" | ${FAIL_IF_EMPTY}
+       ${FAIL_IF_BAD_MACHO} main2
+       # test that auto-hide bit survives ld -r
+       ${LD} -r -arch ${ARCH} other.o -o other-r.o
+       ${OBJECTDUMP} other.o > other.o.dump
+       ${OBJECTDUMP} other-r.o > other-r.o.dump
+       ${PASS_IFF} diff other.o.dump other-r.o.dump 
+       
+clean:
+       rm -f main.o other.o main main2 other-r.o other.o.dump other-r.o.dump 
diff --git a/unit-tests/test-cases/weak-def-auto-hide/main.c b/unit-tests/test-cases/weak-def-auto-hide/main.c
new file mode 100644 (file)
index 0000000..dada6bd
--- /dev/null
@@ -0,0 +1,15 @@
+#include <stdio.h>
+
+void __attribute__((weak)) my_weak()
+{
+}
+
+extern void my_other_weak();
+
+int main()
+{
+       my_weak();
+       my_other_weak();
+       return 0;
+}
+
diff --git a/unit-tests/test-cases/weak-def-auto-hide/other.s b/unit-tests/test-cases/weak-def-auto-hide/other.s
new file mode 100644 (file)
index 0000000..5fd7ec4
--- /dev/null
@@ -0,0 +1,15 @@
+
+
+                       .text
+
+                       .globl _my_weak
+                       .weak_def_can_be_hidden _my_weak
+_my_weak:      nop
+                       nop
+                       
+                       
+                               .globl _my_other_weak
+                               .weak_def_can_be_hidden _my_other_weak
+_my_other_weak:        nop
+                               nop
+       
index e813f498bf1dded9bb43270fc21b9645a362038d..a8d30a9e9e57a3fe49531aadef04726fc646f35f 100644 (file)
@@ -45,4 +45,4 @@ all:
        ${PASS_IFF_GOOD_MACHO} main
        
 clean:
-       rm main main-strip-weak
\ No newline at end of file
+       rm -f main main-strip-weak
\ No newline at end of file
diff --git a/unit-tests/test-cases/weak-force/Makefile b/unit-tests/test-cases/weak-force/Makefile
new file mode 100644 (file)
index 0000000..57712a6
--- /dev/null
@@ -0,0 +1,50 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test
+#
+
+
+run: all
+
+all:   
+       ${CC} ${CCFLAGS} -dynamiclib -Wl,-force_symbols_weak_list foo1.exp foo.c -o libfoo.dylib 
+       ${FAIL_IF_BAD_MACHO} libfoo.dylib
+       nm -m libfoo.dylib | grep _foo1 | grep weak | ${FAIL_IF_EMPTY}
+       nm -m libfoo.dylib | grep _wildcheck | grep weak | ${FAIL_IF_EMPTY}
+       nm -m libfoo.dylib | grep _foo3 | grep weak | ${FAIL_IF_STDIN}
+       nm -m libfoo.dylib | grep _willnot | grep weak | ${FAIL_IF_STDIN}
+       ${CC} ${CCFLAGS} -dynamiclib -Wl,-force_symbols_not_weak_list foo2.exp foo.c -o libfoo.dylib 
+       nm -m libfoo.dylib | grep _foo2 | grep weak | ${FAIL_IF_STDIN}
+       nm -m libfoo.dylib | grep _patterncheck | grep weak | ${FAIL_IF_STDIN}
+       nm -m libfoo.dylib | grep _foo4 | grep weak | ${FAIL_IF_EMPTY}
+       nm -m libfoo.dylib | grep _patnot | grep weak | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} libfoo.dylib
+
+
+               
+clean:
+       rm -rf libfoo.dylib
diff --git a/unit-tests/test-cases/weak-force/foo.c b/unit-tests/test-cases/weak-force/foo.c
new file mode 100644 (file)
index 0000000..baa5755
--- /dev/null
@@ -0,0 +1,17 @@
+
+
+void foo1() {}
+void foo3() {}
+
+
+__attribute__((weak)) void foo2() {}
+__attribute__((weak)) void foo4() {}
+
+
+void wildcheck() {}
+void willnot() {}
+
+
+
+__attribute__((weak)) void patterncheck() {}
+__attribute__((weak)) void patnot() {}
diff --git a/unit-tests/test-cases/weak-force/foo1.exp b/unit-tests/test-cases/weak-force/foo1.exp
new file mode 100644 (file)
index 0000000..7268896
--- /dev/null
@@ -0,0 +1,2 @@
+_foo1
+_wild*
diff --git a/unit-tests/test-cases/weak-force/foo2.exp b/unit-tests/test-cases/weak-force/foo2.exp
new file mode 100644 (file)
index 0000000..1ad4c0d
--- /dev/null
@@ -0,0 +1,2 @@
+_foo2
+_pattern*
index 3b9cdff537a2762764af637ae6506d8f67c8d76c..76c68ba5cc1767c15f2b6b7bdb77efd925d7dbe7 100644 (file)
@@ -15,15 +15,18 @@ extern int bar_data2;
 int* pfoo = &foo_data1;
 int* pbar = &bar_data1;
 
+void* pfoo1;
+void* pbar1;
 
 int main (void)
 {
        // make non-lazy reference to foo1 and bar1
-       if ( &foo1 == &bar1 ) {
-               // make lazy reference to foo2 and bar2
-               foo2();
-               bar2();
-       }
+       pfoo1 = &foo1;
+       pbar1 = &bar1;
+       
+       // make lazy reference to foo2 and bar2
+       foo2();
+       bar2();
    
    // make non-lazy reference to foo_data2 and bar_data2
    return *pfoo + *pbar + foo_data2 + bar_data2;
diff --git a/unit-tests/test-cases/weak_import-local/Makefile b/unit-tests/test-cases/weak_import-local/Makefile
new file mode 100644 (file)
index 0000000..4d21410
--- /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} main.c foo.c -o main
+       ${FAIL_IF_BAD_MACHO} main
+       ${CC} ${CCFLAGS} main.c foo.c -o main -mmacosx-version-min=10.4
+       ${PASS_IFF_GOOD_MACHO} main
+       
+clean:
+       rm -rf main
diff --git a/unit-tests/test-cases/weak_import-local/foo.c b/unit-tests/test-cases/weak_import-local/foo.c
new file mode 100644 (file)
index 0000000..6eabcc7
--- /dev/null
@@ -0,0 +1,7 @@
+
+
+#include "foo.h"
+
+void func2() {}
+int data2 = 0; // weak_import initialized
+
diff --git a/unit-tests/test-cases/weak_import-local/foo.h b/unit-tests/test-cases/weak_import-local/foo.h
new file mode 100644 (file)
index 0000000..1dd4e82
--- /dev/null
@@ -0,0 +1,6 @@
+
+
+extern void func2() __attribute__((weak_import));
+
+extern int data2 __attribute__((weak_import));
+
diff --git a/unit-tests/test-cases/weak_import-local/main.c b/unit-tests/test-cases/weak_import-local/main.c
new file mode 100644 (file)
index 0000000..ce044ad
--- /dev/null
@@ -0,0 +1,18 @@
+#include <stddef.h>
+
+#include "foo.h"
+
+void* pf2 = &func2;
+int* pd2 = &data2;
+
+int main (void)
+{
+       if ( &func2 != NULL )
+               func2();
+       
+       if ( &data2 != NULL )
+               data2 = 1;
+   
+   return 0;
+}
+
index 3266aed568afdfa822f7a4605edc088c3206cffc..a08ed860a99f77a207cf95b82aa7e16e436e3a37 100644 (file)
@@ -1,3 +1,4 @@
+#include <stddef.h>
 
 #include "foo.h"
 
@@ -5,12 +6,14 @@
 int* pdata5 = &data5;
 int* pdata6 = &data6;
 
+void* pf3;
 
 int main (void)
 {
        // make non-lazy reference to func3 and func4
-       if ( &func3 == &func4 ) {
-               // make lazy reference to func3 and func4
+       pf3 = &func3;
+       if ( &func4 == NULL ) {
+               // make lazy reference to func1 and func2
                func1();
                func2();
        }
index 219cdc2c862fdde41bc93e4a159befcf1b1a6c5c..94bf64db534f5f851c8526eeec2d611f460d8e15 100644 (file)
@@ -37,14 +37,17 @@ int bigarray2[2560];
 int bigarray3[25600];
 int bigarray4[256000];
 int bigarray5[2560000];
+#ifndef __arm__
 int bigarray6[256000000*BOOST];
+#endif
 static int staticbigarray1[256];
 static int staticbigarray2[2560];
 static int staticbigarray3[25600];
 static int staticbigarray4[256000];
 static int staticbigarray5[2560000];
+#ifndef __arm__
 static int staticbigarray6[25600000*BOOST];
-
+#endif
 int main()
 {
        staticbigarray1[10] = 4;
@@ -52,7 +55,9 @@ int main()
        staticbigarray3[10] = 4;
        staticbigarray4[10] = 4;
        staticbigarray5[10] = 4;
+#ifndef __arm__
        staticbigarray6[10] = 4;
+#endif
        return 0;
 }