]> git.saurik.com Git - apple/ld64.git/commitdiff
ld64-47.2.tar.gz developer-tools-23 v47.2
authorApple <opensource@apple.com>
Thu, 1 Jun 2006 20:14:06 +0000 (20:14 +0000)
committerApple <opensource@apple.com>
Thu, 1 Jun 2006 20:14:06 +0000 (20:14 +0000)
119 files changed:
ChangeLog [new file with mode: 0644]
ld64.xcode/project.pbxproj [deleted file]
ld64.xcodeproj/project.pbxproj [new file with mode: 0644]
src/Architectures.hpp [new file with mode: 0644]
src/ExecutableFile.h
src/FileAbstraction.hpp [new file with mode: 0644]
src/MachOAbstraction.h [deleted file]
src/MachOFileAbstraction.hpp [new file with mode: 0644]
src/MachOReaderArchive.hpp [new file with mode: 0644]
src/MachOReaderDylib.hpp [new file with mode: 0644]
src/MachOReaderRelocatable.hpp [new file with mode: 0644]
src/MachOWriterExecutable.hpp [new file with mode: 0644]
src/ObjDump.cpp [deleted file]
src/ObjectDump.cpp [new file with mode: 0644]
src/ObjectFile.h
src/Options.cpp
src/Options.cpp.orig [deleted file]
src/Options.h
src/Readers/ObjectFileArchiveMachO.cpp [deleted file]
src/Readers/ObjectFileDylibMachO.cpp [deleted file]
src/Readers/ObjectFileMachO-all.cpp [deleted file]
src/Readers/ObjectFileMachO-all.h [deleted file]
src/Readers/ObjectFileMachO.cpp [deleted file]
src/SectCreate.cpp
src/SectCreate.h
src/Writers/ExecutableFileMachO-all.cpp [deleted file]
src/Writers/ExecutableFileMachO-all.h [deleted file]
src/Writers/ExecutableFileMachO.cpp [deleted file]
src/debugline.c [new file with mode: 0644]
src/debugline.h [new file with mode: 0644]
src/dwarf2.h [new file with mode: 0644]
src/ld.cpp
src/machochecker.cpp [new file with mode: 0644]
unit-tests/README [new file with mode: 0644]
unit-tests/bin/exit-non-zero-pass.pl [new file with mode: 0755]
unit-tests/bin/fail-if-exit-non-zero.pl [new file with mode: 0755]
unit-tests/bin/fail-if-exit-zero.pl [new file with mode: 0755]
unit-tests/bin/fail-if-no-stdin.pl [new file with mode: 0755]
unit-tests/bin/fail-if-stdin.pl [new file with mode: 0755]
unit-tests/bin/fail-iff-exit-zero.pl [new file with mode: 0755]
unit-tests/bin/make-recursive.pl [new file with mode: 0755]
unit-tests/bin/pass-iff-exit-zero.pl [new file with mode: 0755]
unit-tests/bin/pass-iff-no-stdin.pl [new file with mode: 0755]
unit-tests/bin/pass-iff-stdin.pl [new file with mode: 0755]
unit-tests/bin/result-filter.pl [new file with mode: 0755]
unit-tests/include/common.makefile [new file with mode: 0644]
unit-tests/include/test.h [new file with mode: 0644]
unit-tests/run-all-unit-tests [new file with mode: 0755]
unit-tests/test-cases/allow-stack-execute/Makefile [new file with mode: 0644]
unit-tests/test-cases/allow-stack-execute/foo.c [new file with mode: 0644]
unit-tests/test-cases/allowable-client/Makefile [new file with mode: 0644]
unit-tests/test-cases/allowable-client/bar.c [new file with mode: 0644]
unit-tests/test-cases/allowable-client/baz.c [new file with mode: 0644]
unit-tests/test-cases/allowable-client/foo.c [new file with mode: 0644]
unit-tests/test-cases/allowable-client/main.c [new file with mode: 0644]
unit-tests/test-cases/archive-basic/Makefile [new file with mode: 0644]
unit-tests/test-cases/archive-basic/bar.c [new file with mode: 0644]
unit-tests/test-cases/archive-basic/foo.c [new file with mode: 0644]
unit-tests/test-cases/archive-basic/main.c [new file with mode: 0644]
unit-tests/test-cases/archive-weak/Makefile [new file with mode: 0644]
unit-tests/test-cases/archive-weak/bar.c [new file with mode: 0644]
unit-tests/test-cases/archive-weak/baz.c [new file with mode: 0644]
unit-tests/test-cases/archive-weak/foo.c [new file with mode: 0644]
unit-tests/test-cases/archive-weak/main.c [new file with mode: 0644]
unit-tests/test-cases/auto-arch/Makefile [new file with mode: 0644]
unit-tests/test-cases/auto-arch/hello.c [new file with mode: 0644]
unit-tests/test-cases/blank-stubs/Makefile [new file with mode: 0644]
unit-tests/test-cases/blank-stubs/foo.c [new file with mode: 0644]
unit-tests/test-cases/blank-stubs/main.c [new file with mode: 0644]
unit-tests/test-cases/dwarf-debug-notes/Makefile [new file with mode: 0644]
unit-tests/test-cases/dwarf-debug-notes/expected-stabs [new file with mode: 0644]
unit-tests/test-cases/dwarf-debug-notes/header.h [new file with mode: 0644]
unit-tests/test-cases/dwarf-debug-notes/hello.cxx [new file with mode: 0644]
unit-tests/test-cases/dwarf-debug-notes/other.cxx [new file with mode: 0644]
unit-tests/test-cases/dwarf-debug-notes/stabs-filter.pl [new file with mode: 0755]
unit-tests/test-cases/dwarf-ignore/Makefile [new file with mode: 0644]
unit-tests/test-cases/dwarf-ignore/hello.c [new file with mode: 0644]
unit-tests/test-cases/dwarf-strip/Makefile [new file with mode: 0644]
unit-tests/test-cases/dwarf-strip/hello.c [new file with mode: 0644]
unit-tests/test-cases/header-pad/Makefile [new file with mode: 0644]
unit-tests/test-cases/header-pad/hello.c [new file with mode: 0644]
unit-tests/test-cases/hello-world/Makefile [new file with mode: 0644]
unit-tests/test-cases/hello-world/hello.c [new file with mode: 0644]
unit-tests/test-cases/literals-coalesce-alignment/Makefile [new file with mode: 0644]
unit-tests/test-cases/literals-coalesce-alignment/cstring-align-0.s [new file with mode: 0644]
unit-tests/test-cases/literals-coalesce-alignment/cstring-align-3.s [new file with mode: 0644]
unit-tests/test-cases/literals-coalesce/Makefile [new file with mode: 0644]
unit-tests/test-cases/literals-coalesce/literals.s [new file with mode: 0644]
unit-tests/test-cases/multiple-entry-points/Makefile [new file with mode: 0644]
unit-tests/test-cases/multiple-entry-points/test.s [new file with mode: 0644]
unit-tests/test-cases/no-uuid/Makefile [new file with mode: 0644]
unit-tests/test-cases/no-uuid/bar.c [new file with mode: 0644]
unit-tests/test-cases/no-uuid/foo.c [new file with mode: 0644]
unit-tests/test-cases/private-non-lazy/Makefile [new file with mode: 0644]
unit-tests/test-cases/private-non-lazy/bar.c [new file with mode: 0644]
unit-tests/test-cases/private-non-lazy/foo.c [new file with mode: 0644]
unit-tests/test-cases/private-non-lazy/hello.c [new file with mode: 0644]
unit-tests/test-cases/read-only-relocs/Makefile [new file with mode: 0644]
unit-tests/test-cases/read-only-relocs/test.c [new file with mode: 0644]
unit-tests/test-cases/relocs-asm/Makefile [new file with mode: 0644]
unit-tests/test-cases/relocs-asm/relocs-asm.s [new file with mode: 0644]
unit-tests/test-cases/relocs-c/Makefile [new file with mode: 0644]
unit-tests/test-cases/relocs-c/test.c [new file with mode: 0644]
unit-tests/test-cases/relocs-literals/Makefile [new file with mode: 0644]
unit-tests/test-cases/relocs-literals/test.c [new file with mode: 0644]
unit-tests/test-cases/relocs-objc/Makefile [new file with mode: 0644]
unit-tests/test-cases/relocs-objc/test.m [new file with mode: 0644]
unit-tests/test-cases/stabs-coalesce/Makefile [new file with mode: 0644]
unit-tests/test-cases/stabs-coalesce/header.h [new file with mode: 0644]
unit-tests/test-cases/stabs-coalesce/hello.cxx [new file with mode: 0644]
unit-tests/test-cases/stabs-coalesce/other.cxx [new file with mode: 0644]
unit-tests/test-cases/static-executable/Makefile [new file with mode: 0644]
unit-tests/test-cases/static-executable/test.c [new file with mode: 0644]
unit-tests/test-cases/weak_import/Makefile [new file with mode: 0644]
unit-tests/test-cases/weak_import/foo.c [new file with mode: 0644]
unit-tests/test-cases/weak_import/foo.h [new file with mode: 0644]
unit-tests/test-cases/weak_import/main.c [new file with mode: 0644]
unit-tests/test-cases/zero-fill/Makefile [new file with mode: 0644]
unit-tests/test-cases/zero-fill/test.c [new file with mode: 0644]

diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..d028e47
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,691 @@
+
+----- 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
+
+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-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
diff --git a/ld64.xcode/project.pbxproj b/ld64.xcode/project.pbxproj
deleted file mode 100644 (file)
index 1831cbe..0000000
+++ /dev/null
@@ -1,441 +0,0 @@
-// !$*UTF8*$!
-{
-       archiveVersion = 1;
-       classes = {
-       };
-       objectVersion = 39;
-       objects = {
-               F9023C2C06D5A227001BBF46 = {
-                       children = (
-                               F971EED706D5AD240041D381,
-                               F9023C3F06D5A254001BBF46,
-                               F9C0D48A06DD1E1B001C7193,
-                               F9C0D48B06DD1E1B001C7193,
-                               F9023C3E06D5A254001BBF46,
-                               F9023C4006D5A254001BBF46,
-                               F9023C4106D5A254001BBF46,
-                               F97288E607D277570031794D,
-                               F972890007D27FD00031794D,
-                               F9023C4206D5A254001BBF46,
-                               F9023C4806D5A254001BBF46,
-                               F97F5028070D0BB200B9FCD7,
-                               F9023C3A06D5A23E001BBF46,
-                       );
-                       isa = PBXGroup;
-                       refType = 4;
-                       sourceTree = "<group>";
-               };
-               F9023C2E06D5A227001BBF46 = {
-                       buildSettings = {
-                               COPY_PHASE_STRIP = NO;
-                               GCC_OPTIMIZATION_LEVEL = 0;
-                       };
-                       isa = PBXBuildStyle;
-                       name = Development;
-               };
-               F9023C2F06D5A227001BBF46 = {
-                       buildSettings = {
-                               COPY_PHASE_STRIP = YES;
-                       };
-                       isa = PBXBuildStyle;
-                       name = Deployment;
-               };
-               F9023C3006D5A227001BBF46 = {
-                       buildSettings = {
-                       };
-                       buildStyles = (
-                               F9023C2E06D5A227001BBF46,
-                               F9023C2F06D5A227001BBF46,
-                       );
-                       hasScannedForEncodings = 0;
-                       isa = PBXProject;
-                       mainGroup = F9023C2C06D5A227001BBF46;
-                       productRefGroup = F9023C3A06D5A23E001BBF46;
-                       projectDirPath = "";
-                       targets = (
-                               F9023C3806D5A23E001BBF46,
-                               F971EED206D5ACF60041D381,
-                       );
-               };
-               F9023C3606D5A23E001BBF46 = {
-                       buildActionMask = 2147483647;
-                       files = (
-                               F9023C4E06D5A272001BBF46,
-                               F9C0D4BD06DD28D2001C7193,
-                               F9023C4F06D5A272001BBF46,
-                               F9023C5006D5A272001BBF46,
-                               F97288E707D277570031794D,
-                       );
-                       isa = PBXSourcesBuildPhase;
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               F9023C3706D5A23E001BBF46 = {
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       isa = PBXFrameworksBuildPhase;
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               F9023C3806D5A23E001BBF46 = {
-                       buildPhases = (
-                               F9023C3606D5A23E001BBF46,
-                               F9023C3706D5A23E001BBF46,
-                               F97F5025070D0B6300B9FCD7,
-                       );
-                       buildRules = (
-                               F9E8D4BE07FCAF2A00FD5801,
-                               F9E8D4BD07FCAF2000FD5801,
-                       );
-                       buildSettings = {
-                               CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
-                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
-                               GCC_MODEL_TUNING = G5;
-                               GCC_OPTIMIZATION_LEVEL = 3;
-                               INSTALL_PATH = /usr/bin;
-                               OTHER_CFLAGS = "";
-                               OTHER_LDFLAGS = "";
-                               OTHER_REZFLAGS = "";
-                               PREBINDING = NO;
-                               PRODUCT_NAME = ld64;
-                               SECTORDER_FLAGS = "";
-                               VERSIONING_SYSTEM = "apple-generic";
-                               WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
-                       };
-                       dependencies = (
-                       );
-                       isa = PBXNativeTarget;
-                       name = ld64;
-                       productName = ld64;
-                       productReference = F9023C3906D5A23E001BBF46;
-                       productType = "com.apple.product-type.tool";
-               };
-               F9023C3906D5A23E001BBF46 = {
-                       explicitFileType = "compiled.mach-o.executable";
-                       includeInIndex = 0;
-                       isa = PBXFileReference;
-                       path = ld64;
-                       refType = 3;
-                       sourceTree = BUILT_PRODUCTS_DIR;
-               };
-               F9023C3A06D5A23E001BBF46 = {
-                       children = (
-                               F9023C3906D5A23E001BBF46,
-                               F971EED306D5ACF60041D381,
-                       );
-                       isa = PBXGroup;
-                       name = Products;
-                       refType = 4;
-                       sourceTree = "<group>";
-               };
-               F9023C3E06D5A254001BBF46 = {
-                       fileEncoding = 30;
-                       isa = PBXFileReference;
-                       lastKnownFileType = sourcecode.c.h;
-                       name = ExecutableFile.h;
-                       path = src/ExecutableFile.h;
-                       refType = 4;
-                       sourceTree = "<group>";
-               };
-               F9023C3F06D5A254001BBF46 = {
-                       fileEncoding = 30;
-                       isa = PBXFileReference;
-                       lastKnownFileType = sourcecode.cpp.cpp;
-                       name = ld.cpp;
-                       path = src/ld.cpp;
-                       refType = 4;
-                       sourceTree = "<group>";
-               };
-               F9023C4006D5A254001BBF46 = {
-                       fileEncoding = 30;
-                       indentWidth = 4;
-                       isa = PBXFileReference;
-                       lastKnownFileType = sourcecode.c.h;
-                       name = MachOAbstraction.h;
-                       path = src/MachOAbstraction.h;
-                       refType = 4;
-                       sourceTree = "<group>";
-                       tabWidth = 4;
-                       usesTabs = 1;
-               };
-               F9023C4106D5A254001BBF46 = {
-                       fileEncoding = 30;
-                       isa = PBXFileReference;
-                       lastKnownFileType = sourcecode.c.h;
-                       name = ObjectFile.h;
-                       path = src/ObjectFile.h;
-                       refType = 4;
-                       sourceTree = "<group>";
-               };
-               F9023C4206D5A254001BBF46 = {
-                       children = (
-                               F9023C4706D5A254001BBF46,
-                               F9023C4406D5A254001BBF46,
-                               F95DD3B106EE395A007CAFEB,
-                               F9023C4506D5A254001BBF46,
-                               F9023C4606D5A254001BBF46,
-                       );
-                       isa = PBXGroup;
-                       name = Readers;
-                       path = src/Readers;
-                       refType = 4;
-                       sourceTree = "<group>";
-               };
-               F9023C4406D5A254001BBF46 = {
-                       fileEncoding = 30;
-                       isa = PBXFileReference;
-                       lastKnownFileType = sourcecode.cpp.cpp;
-                       path = ObjectFileDylibMachO.cpp;
-                       refType = 4;
-                       sourceTree = "<group>";
-               };
-               F9023C4506D5A254001BBF46 = {
-                       fileEncoding = 30;
-                       isa = PBXFileReference;
-                       lastKnownFileType = sourcecode.cpp.cpp;
-                       path = "ObjectFileMachO-all.cpp";
-                       refType = 4;
-                       sourceTree = "<group>";
-               };
-               F9023C4606D5A254001BBF46 = {
-                       fileEncoding = 30;
-                       isa = PBXFileReference;
-                       lastKnownFileType = sourcecode.c.h;
-                       path = "ObjectFileMachO-all.h";
-                       refType = 4;
-                       sourceTree = "<group>";
-               };
-               F9023C4706D5A254001BBF46 = {
-                       fileEncoding = 30;
-                       isa = PBXFileReference;
-                       lastKnownFileType = sourcecode.cpp.cpp;
-                       path = ObjectFileMachO.cpp;
-                       refType = 4;
-                       sourceTree = "<group>";
-               };
-               F9023C4806D5A254001BBF46 = {
-                       children = (
-                               F9023C4906D5A254001BBF46,
-                               F9023C4A06D5A254001BBF46,
-                               F9023C4B06D5A254001BBF46,
-                       );
-                       isa = PBXGroup;
-                       name = Writers;
-                       path = src/Writers;
-                       refType = 4;
-                       sourceTree = "<group>";
-               };
-               F9023C4906D5A254001BBF46 = {
-                       fileEncoding = 30;
-                       isa = PBXFileReference;
-                       lastKnownFileType = sourcecode.cpp.cpp;
-                       path = "ExecutableFileMachO-all.cpp";
-                       refType = 4;
-                       sourceTree = "<group>";
-               };
-               F9023C4A06D5A254001BBF46 = {
-                       fileEncoding = 30;
-                       isa = PBXFileReference;
-                       lastKnownFileType = sourcecode.c.h;
-                       path = "ExecutableFileMachO-all.h";
-                       refType = 4;
-                       sourceTree = "<group>";
-               };
-               F9023C4B06D5A254001BBF46 = {
-                       fileEncoding = 30;
-                       isa = PBXFileReference;
-                       lastKnownFileType = sourcecode.cpp.cpp;
-                       path = ExecutableFileMachO.cpp;
-                       refType = 4;
-                       sourceTree = "<group>";
-               };
-               F9023C4E06D5A272001BBF46 = {
-                       fileRef = F9023C3F06D5A254001BBF46;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
-               F9023C4F06D5A272001BBF46 = {
-                       fileRef = F9023C4506D5A254001BBF46;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
-               F9023C5006D5A272001BBF46 = {
-                       fileRef = F9023C4906D5A254001BBF46;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
-               F95DD3B106EE395A007CAFEB = {
-                       fileEncoding = 30;
-                       isa = PBXFileReference;
-                       lastKnownFileType = sourcecode.cpp.cpp;
-                       path = ObjectFileArchiveMachO.cpp;
-                       refType = 4;
-                       sourceTree = "<group>";
-               };
-               F971EED006D5ACF60041D381 = {
-                       buildActionMask = 2147483647;
-                       files = (
-                               F971EED806D5AD240041D381,
-                               F971EEDA06D5AD450041D381,
-                       );
-                       isa = PBXSourcesBuildPhase;
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               F971EED106D5ACF60041D381 = {
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       isa = PBXFrameworksBuildPhase;
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               F971EED206D5ACF60041D381 = {
-                       buildPhases = (
-                               F971EED006D5ACF60041D381,
-                               F971EED106D5ACF60041D381,
-                       );
-                       buildRules = (
-                       );
-                       buildSettings = {
-                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
-                               GCC_MODEL_TUNING = G5;
-                               GCC_OPTIMIZATION_LEVEL = 0;
-                               INSTALL_PATH = "$(HOME)/bin";
-                               OTHER_CFLAGS = "";
-                               OTHER_LDFLAGS = "";
-                               OTHER_REZFLAGS = "";
-                               PREBINDING = NO;
-                               PRODUCT_NAME = ObjectDump;
-                               SECTORDER_FLAGS = "";
-                               WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
-                       };
-                       dependencies = (
-                       );
-                       isa = PBXNativeTarget;
-                       name = ObjectDump;
-                       productName = ObjectDump;
-                       productReference = F971EED306D5ACF60041D381;
-                       productType = "com.apple.product-type.tool";
-               };
-               F971EED306D5ACF60041D381 = {
-                       explicitFileType = "compiled.mach-o.executable";
-                       includeInIndex = 0;
-                       isa = PBXFileReference;
-                       path = ObjectDump;
-                       refType = 3;
-                       sourceTree = BUILT_PRODUCTS_DIR;
-               };
-               F971EED706D5AD240041D381 = {
-                       fileEncoding = 30;
-                       isa = PBXFileReference;
-                       lastKnownFileType = sourcecode.cpp.cpp;
-                       name = ObjDump.cpp;
-                       path = src/ObjDump.cpp;
-                       refType = 4;
-                       sourceTree = "<group>";
-               };
-               F971EED806D5AD240041D381 = {
-                       fileRef = F971EED706D5AD240041D381;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
-               F971EEDA06D5AD450041D381 = {
-                       fileRef = F9023C4506D5A254001BBF46;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
-               F97288E607D277570031794D = {
-                       fileEncoding = 30;
-                       isa = PBXFileReference;
-                       lastKnownFileType = sourcecode.cpp.cpp;
-                       name = SectCreate.cpp;
-                       path = src/SectCreate.cpp;
-                       refType = 4;
-                       sourceTree = "<group>";
-               };
-               F97288E707D277570031794D = {
-                       fileRef = F97288E607D277570031794D;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
-               F972890007D27FD00031794D = {
-                       fileEncoding = 30;
-                       isa = PBXFileReference;
-                       lastKnownFileType = sourcecode.c.h;
-                       name = SectCreate.h;
-                       path = src/SectCreate.h;
-                       refType = 4;
-                       sourceTree = "<group>";
-               };
-               F97F5025070D0B6300B9FCD7 = {
-                       buildActionMask = 8;
-                       dstPath = /usr/share/man/man1;
-                       dstSubfolderSpec = 0;
-                       files = (
-                               F97F5029070D0BB200B9FCD7,
-                       );
-                       isa = PBXCopyFilesBuildPhase;
-                       runOnlyForDeploymentPostprocessing = 1;
-               };
-               F97F5028070D0BB200B9FCD7 = {
-                       fileEncoding = 30;
-                       isa = PBXFileReference;
-                       lastKnownFileType = text.man;
-                       name = ld64.1;
-                       path = doc/man/man1/ld64.1;
-                       refType = 4;
-                       sourceTree = "<group>";
-               };
-               F97F5029070D0BB200B9FCD7 = {
-                       fileRef = F97F5028070D0BB200B9FCD7;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
-               F9C0D48A06DD1E1B001C7193 = {
-                       fileEncoding = 30;
-                       isa = PBXFileReference;
-                       lastKnownFileType = sourcecode.cpp.cpp;
-                       name = Options.cpp;
-                       path = src/Options.cpp;
-                       refType = 4;
-                       sourceTree = "<group>";
-               };
-               F9C0D48B06DD1E1B001C7193 = {
-                       fileEncoding = 30;
-                       isa = PBXFileReference;
-                       lastKnownFileType = sourcecode.c.h;
-                       name = Options.h;
-                       path = src/Options.h;
-                       refType = 4;
-                       sourceTree = "<group>";
-               };
-               F9C0D4BD06DD28D2001C7193 = {
-                       fileRef = F9C0D48A06DD1E1B001C7193;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
-               F9E8D4BD07FCAF2000FD5801 = {
-                       compilerSpec = com.apple.compilers.gcc.4_0;
-                       fileType = sourcecode.c;
-                       isEditable = 1;
-                       isa = PBXBuildRule;
-                       outputFiles = (
-                       );
-               };
-               F9E8D4BE07FCAF2A00FD5801 = {
-                       compilerSpec = com.apple.compilers.gcc.4_0;
-                       fileType = sourcecode.cpp;
-                       isEditable = 1;
-                       isa = PBXBuildRule;
-                       outputFiles = (
-                       );
-               };
-       };
-       rootObject = F9023C3006D5A227001BBF46;
-}
diff --git a/ld64.xcodeproj/project.pbxproj b/ld64.xcodeproj/project.pbxproj
new file mode 100644 (file)
index 0000000..1ce18dd
--- /dev/null
@@ -0,0 +1,602 @@
+// !$*UTF8*$!
+{
+       archiveVersion = 1;
+       classes = {
+       };
+       objectVersion = 42;
+       objects = {
+
+/* Begin PBXAggregateTarget section */
+               F96D5368094A2754008E9EE8 /* unit-tests */ = {
+                       isa = PBXAggregateTarget;
+                       buildConfigurationList = F96D536D094A2773008E9EE8 /* Build configuration list for PBXAggregateTarget "unit-tests" */;
+                       buildPhases = (
+                               F96D5367094A2754008E9EE8 /* ShellScript */,
+                       );
+                       buildSettings = {
+                               PRODUCT_NAME = "unit-tests";
+                       };
+                       dependencies = (
+                               F96D536A094A275D008E9EE8 /* PBXTargetDependency */,
+                               F96D536C094A275F008E9EE8 /* PBXTargetDependency */,
+                               F9EA73970974999B008B4F1D /* PBXTargetDependency */,
+                       );
+                       name = "unit-tests";
+                       productName = "unit-tests";
+               };
+/* End PBXAggregateTarget section */
+
+/* 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 */; };
+               F97288E707D277570031794D /* SectCreate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F97288E607D277570031794D /* SectCreate.cpp */; };
+               F97F5029070D0BB200B9FCD7 /* ld64.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = F97F5028070D0BB200B9FCD7 /* ld64.1 */; };
+               F9C0D4BD06DD28D2001C7193 /* Options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9C0D48A06DD1E1B001C7193 /* Options.cpp */; };
+               F9EA72D5097454FF008B4F1D /* machochecker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9EA72D4097454FF008B4F1D /* machochecker.cpp */; };
+               F9EA7584097882F3008B4F1D /* debugline.c in Sources */ = {isa = PBXBuildFile; fileRef = F9EA7582097882F3008B4F1D /* debugline.c */; };
+               F9EA75BC09788857008B4F1D /* debugline.c in Sources */ = {isa = PBXBuildFile; fileRef = F9EA7582097882F3008B4F1D /* debugline.c */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXBuildRule section */
+               F9E8D4BD07FCAF2000FD5801 /* PBXBuildRule */ = {
+                       isa = PBXBuildRule;
+                       compilerSpec = com.apple.compilers.gcc.4_0;
+                       fileType = sourcecode.c;
+                       isEditable = 1;
+                       outputFiles = (
+                       );
+               };
+               F9E8D4BE07FCAF2A00FD5801 /* PBXBuildRule */ = {
+                       isa = PBXBuildRule;
+                       compilerSpec = com.apple.compilers.gcc.4_0;
+                       fileType = sourcecode.cpp;
+                       isEditable = 1;
+                       outputFiles = (
+                       );
+               };
+/* End PBXBuildRule section */
+
+/* Begin PBXBuildStyle section */
+               F933D92F09291D070083EAC8 /* Development */ = {
+                       isa = PBXBuildStyle;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = NO;
+                       };
+                       name = Development;
+               };
+               F933D93009291D070083EAC8 /* Deployment */ = {
+                       isa = PBXBuildStyle;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = YES;
+                       };
+                       name = Deployment;
+               };
+/* End PBXBuildStyle section */
+
+/* Begin PBXContainerItemProxy section */
+               F96D5369094A275D008E9EE8 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = F9023C3006D5A227001BBF46 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = F9023C3806D5A23E001BBF46;
+                       remoteInfo = ld;
+               };
+               F96D536B094A275F008E9EE8 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = F9023C3006D5A227001BBF46 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = F971EED206D5ACF60041D381;
+                       remoteInfo = ObjectDump;
+               };
+               F9EA73960974999B008B4F1D /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = F9023C3006D5A227001BBF46 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = F9EA72CA097454A6008B4F1D;
+                       remoteInfo = machocheck;
+               };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+               F97F5025070D0B6300B9FCD7 /* CopyFiles */ = {
+                       isa = PBXCopyFilesBuildPhase;
+                       buildActionMask = 8;
+                       dstPath = /usr/share/man/man1;
+                       dstSubfolderSpec = 0;
+                       files = (
+                               F97F5029070D0BB200B9FCD7 /* ld64.1 in CopyFiles */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+               };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+               C02A29DE0953B26E001FB8C1 /* ChangeLog */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = ChangeLog; sourceTree = "<group>"; };
+               F9023C3906D5A23E001BBF46 /* ld64 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ld64; sourceTree = BUILT_PRODUCTS_DIR; };
+               F9023C3E06D5A254001BBF46 /* ExecutableFile.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ExecutableFile.h; path = src/ExecutableFile.h; sourceTree = "<group>"; };
+               F9023C3F06D5A254001BBF46 /* ld.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ld.cpp; path = src/ld.cpp; sourceTree = "<group>"; };
+               F9023C4106D5A254001BBF46 /* ObjectFile.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ObjectFile.h; path = src/ObjectFile.h; sourceTree = "<group>"; };
+               F933D9460929277C0083EAC8 /* FileAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = FileAbstraction.hpp; path = src/FileAbstraction.hpp; sourceTree = "<group>"; };
+               F933D9470929277C0083EAC8 /* MachOFileAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = MachOFileAbstraction.hpp; path = src/MachOFileAbstraction.hpp; sourceTree = "<group>"; };
+               F933DC37092A82480083EAC8 /* Architectures.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Architectures.hpp; path = src/Architectures.hpp; sourceTree = "<group>"; };
+               F933E3CB092E84250083EAC8 /* MachOReaderArchive.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = MachOReaderArchive.hpp; path = src/MachOReaderArchive.hpp; sourceTree = "<group>"; };
+               F933E3CC092E84250083EAC8 /* MachOReaderDylib.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = MachOReaderDylib.hpp; path = src/MachOReaderDylib.hpp; sourceTree = "<group>"; };
+               F933E3CD092E84250083EAC8 /* MachOReaderRelocatable.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = MachOReaderRelocatable.hpp; path = src/MachOReaderRelocatable.hpp; sourceTree = "<group>"; };
+               F933E3CE092E84250083EAC8 /* MachOWriterExecutable.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = MachOWriterExecutable.hpp; path = src/MachOWriterExecutable.hpp; 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/ObjectDump.cpp; sourceTree = "<group>"; };
+               F97288E607D277570031794D /* SectCreate.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = SectCreate.cpp; path = src/SectCreate.cpp; sourceTree = "<group>"; };
+               F972890007D27FD00031794D /* SectCreate.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = SectCreate.h; path = src/SectCreate.h; sourceTree = "<group>"; };
+               F97F5028070D0BB200B9FCD7 /* ld64.1 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.man; name = ld64.1; path = doc/man/man1/ld64.1; sourceTree = "<group>"; };
+               F9C0D48A06DD1E1B001C7193 /* Options.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Options.cpp; path = src/Options.cpp; sourceTree = "<group>"; };
+               F9C0D48B06DD1E1B001C7193 /* Options.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Options.h; path = src/Options.h; sourceTree = "<group>"; };
+               F9EA72CB097454A6008B4F1D /* machocheck */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = machocheck; sourceTree = BUILT_PRODUCTS_DIR; };
+               F9EA72D4097454FF008B4F1D /* machochecker.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = machochecker.cpp; path = src/machochecker.cpp; sourceTree = "<group>"; };
+               F9EA7582097882F3008B4F1D /* debugline.c */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.c; name = debugline.c; path = src/debugline.c; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+               F9EA7583097882F3008B4F1D /* debugline.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = debugline.h; path = src/debugline.h; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+               F9023C3706D5A23E001BBF46 /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               F971EED106D5ACF60041D381 /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               F9EA72C9097454A6008B4F1D /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+               F9023C2C06D5A227001BBF46 = {
+                       isa = PBXGroup;
+                       children = (
+                               C02A29DE0953B26E001FB8C1 /* ChangeLog */,
+                               F933DC37092A82480083EAC8 /* Architectures.hpp */,
+                               F933D9460929277C0083EAC8 /* FileAbstraction.hpp */,
+                               F933D9470929277C0083EAC8 /* MachOFileAbstraction.hpp */,
+                               F933E3CD092E84250083EAC8 /* MachOReaderRelocatable.hpp */,
+                               F933E3CB092E84250083EAC8 /* MachOReaderArchive.hpp */,
+                               F933E3CC092E84250083EAC8 /* MachOReaderDylib.hpp */,
+                               F933E3CE092E84250083EAC8 /* MachOWriterExecutable.hpp */,
+                               F9023C3E06D5A254001BBF46 /* ExecutableFile.h */,
+                               F9023C4106D5A254001BBF46 /* ObjectFile.h */,
+                               F9023C3F06D5A254001BBF46 /* ld.cpp */,
+                               F9C0D48A06DD1E1B001C7193 /* Options.cpp */,
+                               F9C0D48B06DD1E1B001C7193 /* Options.h */,
+                               F97288E607D277570031794D /* SectCreate.cpp */,
+                               F972890007D27FD00031794D /* SectCreate.h */,
+                               F9EA7582097882F3008B4F1D /* debugline.c */,
+                               F9EA7583097882F3008B4F1D /* debugline.h */,
+                               F9EA72D4097454FF008B4F1D /* machochecker.cpp */,
+                               F971EED706D5AD240041D381 /* ObjectDump.cpp */,
+                               F97F5028070D0BB200B9FCD7 /* ld64.1 */,
+                               F9023C3A06D5A23E001BBF46 /* Products */,
+                       );
+                       sourceTree = "<group>";
+               };
+               F9023C3A06D5A23E001BBF46 /* Products */ = {
+                       isa = PBXGroup;
+                       children = (
+                               F9023C3906D5A23E001BBF46 /* ld64 */,
+                               F971EED306D5ACF60041D381 /* ObjectDump */,
+                               F9EA72CB097454A6008B4F1D /* machocheck */,
+                       );
+                       name = Products;
+                       sourceTree = "<group>";
+               };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+               F9023C3806D5A23E001BBF46 /* ld */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = F933D91B09291AC90083EAC8 /* Build configuration list for PBXNativeTarget "ld" */;
+                       buildPhases = (
+                               F9023C3606D5A23E001BBF46 /* Sources */,
+                               F9023C3706D5A23E001BBF46 /* Frameworks */,
+                               F97F5025070D0B6300B9FCD7 /* CopyFiles */,
+                       );
+                       buildRules = (
+                               F9E8D4BE07FCAF2A00FD5801 /* PBXBuildRule */,
+                               F9E8D4BD07FCAF2000FD5801 /* PBXBuildRule */,
+                       );
+                       buildSettings = {
+                               PRODUCT_NAME = ld64;
+                       };
+                       dependencies = (
+                       );
+                       name = ld;
+                       productName = ld64;
+                       productReference = F9023C3906D5A23E001BBF46 /* ld64 */;
+                       productType = "com.apple.product-type.tool";
+               };
+               F971EED206D5ACF60041D381 /* ObjectDump */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = F933D91F09291AC90083EAC8 /* Build configuration list for PBXNativeTarget "ObjectDump" */;
+                       buildPhases = (
+                               F971EED006D5ACF60041D381 /* Sources */,
+                               F971EED106D5ACF60041D381 /* Frameworks */,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               PRODUCT_NAME = ObjectDump;
+                       };
+                       dependencies = (
+                       );
+                       name = ObjectDump;
+                       productName = ObjectDump;
+                       productReference = F971EED306D5ACF60041D381 /* ObjectDump */;
+                       productType = "com.apple.product-type.tool";
+               };
+               F9EA72CA097454A6008B4F1D /* machocheck */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = F9EA72CF097454D5008B4F1D /* Build configuration list for PBXNativeTarget "machocheck" */;
+                       buildPhases = (
+                               F9EA72C8097454A6008B4F1D /* Sources */,
+                               F9EA72C9097454A6008B4F1D /* Frameworks */,
+                       );
+                       buildRules = (
+                       );
+                       buildSettings = {
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               GCC_MODEL_TUNING = G5;
+                               INSTALL_PATH = "$(HOME)/bin";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = machocheck;
+                       };
+                       dependencies = (
+                       );
+                       name = machocheck;
+                       productName = machocheck;
+                       productReference = F9EA72CB097454A6008B4F1D /* machocheck */;
+                       productType = "com.apple.product-type.tool";
+               };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+               F9023C3006D5A227001BBF46 /* Project object */ = {
+                       isa = PBXProject;
+                       buildConfigurationList = F933D92309291AC90083EAC8 /* Build configuration list for PBXProject "ld64" */;
+                       buildSettings = {
+                       };
+                       buildStyles = (
+                               F933D92F09291D070083EAC8 /* Development */,
+                               F933D93009291D070083EAC8 /* Deployment */,
+                       );
+                       hasScannedForEncodings = 0;
+                       mainGroup = F9023C2C06D5A227001BBF46;
+                       productRefGroup = F9023C3A06D5A23E001BBF46 /* Products */;
+                       projectDirPath = "";
+                       targets = (
+                               F9023C3806D5A23E001BBF46 /* ld */,
+                               F971EED206D5ACF60041D381 /* ObjectDump */,
+                               F9EA72CA097454A6008B4F1D /* machocheck */,
+                               F96D5368094A2754008E9EE8 /* unit-tests */,
+                       );
+               };
+/* End PBXProject section */
+
+/* Begin PBXShellScriptBuildPhase section */
+               F96D5367094A2754008E9EE8 /* ShellScript */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       inputPaths = (
+                       );
+                       outputPaths = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+                       shellPath = /bin/csh;
+                       shellScript = "# Let tests set MACOSX_DEPLOYMENT_TARGET as they need\nunsetenv MACOSX_DEPLOYMENT_TARGET\n\n# make an symlink to ld64 called ld, so that gcc will use this linker for all linking\nrm -rf $BUILT_PRODUCTS_DIR/ld\nln -s $BUILT_PRODUCTS_DIR/ld64 $BUILT_PRODUCTS_DIR/ld\n\n# run full test suite\n$SRCROOT/unit-tests/run-all-unit-tests\n\nexit 0";
+               };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+               F9023C3606D5A23E001BBF46 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               F9023C4E06D5A272001BBF46 /* ld.cpp in Sources */,
+                               F9C0D4BD06DD28D2001C7193 /* Options.cpp in Sources */,
+                               F97288E707D277570031794D /* SectCreate.cpp in Sources */,
+                               F9EA7584097882F3008B4F1D /* debugline.c in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               F971EED006D5ACF60041D381 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               F933E3D9092E855B0083EAC8 /* ObjectDump.cpp in Sources */,
+                               F9EA75BC09788857008B4F1D /* debugline.c in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               F9EA72C8097454A6008B4F1D /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               F9EA72D5097454FF008B4F1D /* machochecker.cpp in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+               F96D536A094A275D008E9EE8 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = F9023C3806D5A23E001BBF46 /* ld */;
+                       targetProxy = F96D5369094A275D008E9EE8 /* PBXContainerItemProxy */;
+               };
+               F96D536C094A275F008E9EE8 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = F971EED206D5ACF60041D381 /* ObjectDump */;
+                       targetProxy = F96D536B094A275F008E9EE8 /* PBXContainerItemProxy */;
+               };
+               F9EA73970974999B008B4F1D /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = F9EA72CA097454A6008B4F1D /* machocheck */;
+                       targetProxy = F9EA73960974999B008B4F1D /* PBXContainerItemProxy */;
+               };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+               F933D91C09291AC90083EAC8 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = NO;
+                               CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
+                               GCC_DYNAMIC_NO_PIC = YES;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+                               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;
+                               INSTALL_PATH = /usr/bin;
+                               OTHER_CPLUSPLUSFLAGS = "$(OTHER_CPLUSPLUSFLAGS)";
+                               OTHER_LDFLAGS = "";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = ld64;
+                               SECTORDER_FLAGS = "";
+                               VERSIONING_SYSTEM = "apple-generic";
+                               WARNING_CFLAGS = "-Wall";
+                       };
+                       name = Debug;
+               };
+               F933D91D09291AC90083EAC8 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = YES;
+                               CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
+                               GCC_DYNAMIC_NO_PIC = YES;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_OPTIMIZATION_LEVEL = 3;
+                               GCC_PREPROCESSOR_DEFINITIONS = "$(GCC_PREPROCESSOR_DEFINITIONS_$(RC_RELEASE))";
+                               GCC_PREPROCESSOR_DEFINITIONS_Curry = __OPEN_SOURCE__;
+                               GCC_PREPROCESSOR_DEFINITIONS_CurryWeed = __OPEN_SOURCE__;
+                               GCC_PREPROCESSOR_DEFINITIONS_Leopard = __OPEN_SOURCE__;
+                               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;
+                               INSTALL_PATH = /usr/bin;
+                               OTHER_CPLUSPLUSFLAGS = "$(OTHER_CPLUSPLUSFLAGS)";
+                               OTHER_LDFLAGS = "";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = ld64;
+                               SECTORDER_FLAGS = "";
+                               VERSIONING_SYSTEM = "apple-generic";
+                               WARNING_CFLAGS = "-Wall";
+                       };
+                       name = Release;
+               };
+               F933D92009291AC90083EAC8 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               INSTALL_PATH = "$(HOME)/bin";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = ObjectDump;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = (
+                                       "-Wmost",
+                                       "-Wno-four-char-constants",
+                                       "-Wno-unknown-pragmas",
+                               );
+                       };
+                       name = Debug;
+               };
+               F933D92109291AC90083EAC8 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = YES;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               INSTALL_PATH = "$(HOME)/bin";
+                               OTHER_LDFLAGS = "";
+                               OTHER_REZFLAGS = "";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = ObjectDump;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = (
+                                       "-Wmost",
+                                       "-Wno-four-char-constants",
+                                       "-Wno-unknown-pragmas",
+                               );
+                       };
+                       name = Release;
+               };
+               F933D92409291AC90083EAC8 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+                       };
+                       name = Debug;
+               };
+               F933D92509291AC90083EAC8 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+                       };
+                       name = Release;
+               };
+               F96D536E094A2773008E9EE8 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               PRODUCT_NAME = "unit-tests";
+                       };
+                       name = Debug;
+               };
+               F96D536F094A2773008E9EE8 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = YES;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               PRODUCT_NAME = "unit-tests";
+                       };
+                       name = Release;
+               };
+               F9EA72D0097454D5008B4F1D /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               GCC_MODEL_TUNING = G5;
+                               INSTALL_PATH = "$(HOME)/bin";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = machocheck;
+                       };
+                       name = Debug;
+               };
+               F9EA72D1097454D5008B4F1D /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = YES;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               GCC_MODEL_TUNING = G5;
+                               INSTALL_PATH = "$(HOME)/bin";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = machocheck;
+                       };
+                       name = Release;
+               };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+               F933D91B09291AC90083EAC8 /* Build configuration list for PBXNativeTarget "ld" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               F933D91C09291AC90083EAC8 /* Debug */,
+                               F933D91D09291AC90083EAC8 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
+               F933D91F09291AC90083EAC8 /* Build configuration list for PBXNativeTarget "ObjectDump" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               F933D92009291AC90083EAC8 /* Debug */,
+                               F933D92109291AC90083EAC8 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
+               F933D92309291AC90083EAC8 /* Build configuration list for PBXProject "ld64" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               F933D92409291AC90083EAC8 /* Debug */,
+                               F933D92509291AC90083EAC8 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
+               F96D536D094A2773008E9EE8 /* Build configuration list for PBXAggregateTarget "unit-tests" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               F96D536E094A2773008E9EE8 /* Debug */,
+                               F96D536F094A2773008E9EE8 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
+               F9EA72CF097454D5008B4F1D /* Build configuration list for PBXNativeTarget "machocheck" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               F9EA72D0097454D5008B4F1D /* Debug */,
+                               F9EA72D1097454D5008B4F1D /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
+/* End XCConfigurationList section */
+       };
+       rootObject = F9023C3006D5A227001BBF46 /* Project object */;
+}
diff --git a/src/Architectures.hpp b/src/Architectures.hpp
new file mode 100644 (file)
index 0000000..71c10c4
--- /dev/null
@@ -0,0 +1,70 @@
+/* -*- 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 __ARCHITECTURES__
+#define __ARCHITECTURES__
+
+#include "FileAbstraction.hpp"
+
+
+//
+// Architectures
+//
+struct ppc
+{
+       typedef Pointer32<BigEndian>            P;
+       
+       enum ReferenceKinds {  kNoFixUp, kFollowOn, kPointer, kPointerWeakImport, kPointerDiff32, kPointerDiff64,
+                                                       kBranch24, kBranch24WeakImport, kBranch14,
+                                                       kPICBaseLow16, kPICBaseLow14, kPICBaseHigh16, 
+                                                       kAbsLow16, kAbsLow14, kAbsHigh16, kAbsHigh16AddLow };
+};
+
+struct ppc64
+{
+       typedef Pointer64<BigEndian>            P;
+       
+       enum ReferenceKinds {  kNoFixUp, kFollowOn, kPointer, kPointerWeakImport, kPointerDiff32, kPointerDiff64,
+                                                       kBranch24, kBranch24WeakImport, kBranch14,
+                                                       kPICBaseLow16, kPICBaseLow14, kPICBaseHigh16, 
+                                                       kAbsLow16, kAbsLow14, kAbsHigh16, kAbsHigh16AddLow };
+};
+
+struct x86
+{
+       typedef Pointer32<LittleEndian>         P;
+       
+       enum ReferenceKinds {  kNoFixUp, kFollowOn, kPointer, kPointerWeakImport, kPointerDiff, 
+                                                       kPCRel32, kPCRel32WeakImport };
+};
+
+
+
+
+
+
+
+#endif // __ARCHITECTURES__
+
+
index e2e1e8c6e15c507b53084a90b23ae99e2dfb1f5d..576554c65336a6db04a18dd71f511db502eb5e73 100644 (file)
@@ -1,15 +1,16 @@
-/*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+/* -*- 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,
  * 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__
 
 
 namespace ExecutableFile {
 
-       struct DyLibUsed 
+       struct DyLibUsed
        {
                ObjectFile::Reader*             reader;
                DynamicLibraryOptions   options;
-               bool                                    indirect;               // library found indirect.  Do not make load command
+               bool                                    indirect;       // library found indirect.  Do not make load command
                ObjectFile::Reader*             directReader;   // direct library which re-exports this library
        };
-       
+
        class Writer : public ObjectFile::Reader
        {
-       public:         
-               virtual                                                         ~Writer() {};
-               
+       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 std::vector<ObjectFile::StabsInfo>*             getStabsDebugInfo() = 0;
 
                virtual class ObjectFile::Atom*                                 getUndefinedProxyAtom(const char* name) = 0;
-               virtual void                                                                    write(std::vector<class ObjectFile::Atom*>& atoms, class ObjectFile::Atom* entryPointAtom) = 0;
-
-
+               virtual uint64_t                                                                write(std::vector<class ObjectFile::Atom*>& atoms,
+                                                                                                                         std::vector<class ObjectFile::Reader::Stab>& stabs,
+                                                                                                                         class ObjectFile::Atom* entryPointAtom,
+                                                                                                                         class ObjectFile::Atom* dyldHelperAtom,
+                                                                                                                         bool createUUID) = 0;
 
        protected:
-                                                                                       Writer(std::vector<DyLibUsed>&) {};
+                                                                       Writer(std::vector<DyLibUsed>&) {};
        };
 
 };
 
-
-
-
 #endif // __EXECUTABLEFILE__
-
-
-
diff --git a/src/FileAbstraction.hpp b/src/FileAbstraction.hpp
new file mode 100644 (file)
index 0000000..1f7a629
--- /dev/null
@@ -0,0 +1,145 @@
+/* -*- 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 __FILE_ABSTRACTION__
+#define __FILE_ABSTRACTION__
+
+
+#include <stdint.h>
+#include <string.h>
+#include <libkern/OSByteOrder.h>
+
+#ifdef __OPTIMIZE__
+#define INLINE __attribute__((always_inline))
+#else
+#define INLINE
+#endif
+
+//
+// This abstraction layer is for use with file formats that have 64-bit/32-bit and Big-Endian/Little-Endian variants
+//
+// For example: to make a utility that handles 32-bit little enidan files use:  Pointer32<LittleEndian>
+//
+//
+//             get16()                 read a 16-bit number from an E endian struct
+//             set16()                 write a 16-bit number to an E endian struct
+//             get32()                 read a 32-bit number from an E endian struct
+//             set32()                 write a 32-bit number to an E endian struct
+//             get64()                 read a 64-bit number from an E endian struct
+//             set64()                 write a 64-bit number to an E endian struct
+//
+//             getBits()               read a bit field from an E endian struct (bitCount=number of bits in field, firstBit=bit index of field)
+//             setBits()               write a bit field to an E endian struct (bitCount=number of bits in field, firstBit=bit index of field)
+//
+//             getBitsRaw()    read a bit field from a struct with native endianness
+//             setBitsRaw()    write a bit field from a struct with native endianness
+//
+
+class BigEndian
+{
+public:
+       static uint16_t get16(const uint16_t& from)                             INLINE { return OSReadBigInt16(&from, 0); }
+       static void             set16(uint16_t& into, uint16_t value)   INLINE { OSWriteBigInt16(&into, 0, value); }
+       
+       static uint32_t get32(const uint32_t& from)                             INLINE { return OSReadBigInt32(&from, 0); }
+       static void             set32(uint32_t& into, uint32_t value)   INLINE { OSWriteBigInt32(&into, 0, value); }
+       
+       static uint64_t get64(const uint64_t& from)                             INLINE { return OSReadBigInt64(&from, 0); }
+       static void             set64(uint64_t& into, uint64_t value)   INLINE { OSWriteBigInt64(&into, 0, value); }
+       
+       static uint32_t getBits(const uint32_t& from, 
+                                               uint8_t firstBit, uint8_t bitCount)     INLINE { return getBitsRaw(get32(from), firstBit, bitCount); }
+       static void             setBits(uint32_t& into, uint32_t value,
+                                               uint8_t firstBit, uint8_t bitCount)     INLINE { uint32_t temp = get32(into); setBitsRaw(temp, value, firstBit, bitCount); set32(into, temp); }
+
+       static uint32_t getBitsRaw(const uint32_t& from, 
+                                               uint8_t firstBit, uint8_t bitCount)     INLINE { return ((from >> (32-firstBit-bitCount)) & ((1<<bitCount)-1)); }
+       static void             setBitsRaw(uint32_t& into, uint32_t value,
+                                               uint8_t firstBit, uint8_t bitCount)     INLINE { uint32_t temp = into; 
+                                                                                                                                                                                       const uint32_t mask = ((1<<bitCount)-1); 
+                                                                                                                                                                                       temp &= ~(mask << (32-firstBit-bitCount)); 
+                                                                                                                                                                                       temp |= ((value & mask) << (32-firstBit-bitCount)); 
+                                                                                                                                                                                       into = temp; }
+       enum { little_endian = 0 };
+};
+
+
+class LittleEndian
+{
+public:
+       static uint16_t get16(const uint16_t& from)                             INLINE { return OSReadLittleInt16(&from, 0); }
+       static void             set16(uint16_t& into, uint16_t value)   INLINE { OSWriteLittleInt16(&into, 0, value); }
+       
+       static uint32_t get32(const uint32_t& from)                             INLINE { return OSReadLittleInt32(&from, 0); }
+       static void             set32(uint32_t& into, uint32_t value)   INLINE { OSWriteLittleInt32(&into, 0, value); }
+       
+       static uint64_t get64(const uint64_t& from)                             INLINE { return OSReadLittleInt64(&from, 0); }
+       static void             set64(uint64_t& into, uint64_t value)   INLINE { OSWriteLittleInt64(&into, 0, value); }
+
+       static uint32_t getBits(const uint32_t& from,
+                                               uint8_t firstBit, uint8_t bitCount)     INLINE { return getBitsRaw(get32(from), firstBit, bitCount); }
+       static void             setBits(uint32_t& into, uint32_t value,
+                                               uint8_t firstBit, uint8_t bitCount)     INLINE { uint32_t temp = get32(into); setBitsRaw(temp, value, firstBit, bitCount); set32(into, temp); }
+
+       static uint32_t getBitsRaw(const uint32_t& from,
+                                               uint8_t firstBit, uint8_t bitCount)     INLINE { return ((from >> firstBit) & ((1<<bitCount)-1)); }
+       static void             setBitsRaw(uint32_t& into, uint32_t value,
+                                               uint8_t firstBit, uint8_t bitCount)     INLINE {  uint32_t temp = into; 
+                                                                                                                                                                                       const uint32_t mask = ((1<<bitCount)-1); 
+                                                                                                                                                                                       temp &= ~(mask << firstBit); 
+                                                                                                                                                                                       temp |= ((value & mask) << firstBit); 
+                                                                                                                                                                                       into = temp; }
+       enum { little_endian = 1 };
+};
+
+
+template <typename _E>
+class Pointer32
+{
+public:
+       typedef uint32_t        uint_t;
+       typedef _E                      E;
+       
+       static uint64_t getP(const uint_t& from)                                INLINE { return _E::get32(from); }
+       static void             setP(uint_t& into, uint64_t value)              INLINE { _E::set32(into, value); }
+};
+
+
+template <typename _E>
+class Pointer64
+{
+public:
+       typedef uint64_t        uint_t;
+       typedef _E                      E;
+       
+       static uint64_t getP(const uint_t& from)                                INLINE { return _E::get64(from); }
+       static void             setP(uint_t& into, uint64_t value)              INLINE { _E::set64(into, value); }
+};
+
+
+
+
+
+#endif // __FILE_ABSTRACTION__
+
+
diff --git a/src/MachOAbstraction.h b/src/MachOAbstraction.h
deleted file mode 100644 (file)
index fe4b01e..0000000
+++ /dev/null
@@ -1,2009 +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@
- */
-#include <stdint.h>
-#include <string.h>
-#include <mach-o/nlist.h>
-#include <mach-o/loader.h>
-#include <libkern/OSByteOrder.h>
-
-
-#undef ENDIAN_READ16
-#undef ENDIAN_WRITE16
-#undef ENDIAN_READ32
-#undef ENDIAN_WRITE32
-#undef ENDIAN_SWAP64
-#undef ENDIAN_SWAP_POINTER
-
-#if defined(MACHO_32_SAME_ENDIAN) || defined(MACHO_64_SAME_ENDIAN)
-       #define ENDIAN_READ16(x)                        (x)
-       #define ENDIAN_WRITE16(into, value) into = (value);
-       
-       #define ENDIAN_READ32(x)                        (x)
-       #define ENDIAN_WRITE32(into, value) into = (value);
-
-       #define ENDIAN_SWAP64(x)                        (x)
-       
-#elif defined(MACHO_32_OPPOSITE_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
-       #define ENDIAN_READ16(x)                        OSReadSwapInt16((uint16_t*)&(x), 0)
-       #define ENDIAN_WRITE16(into, value)     OSWriteSwapInt16(&(into), 0, value);
-
-       #define ENDIAN_READ32(x)                        OSReadSwapInt32((uint32_t*)&(x), 0)
-       #define ENDIAN_WRITE32(into, value) OSWriteSwapInt32(&(into), 0, value);
-       
-       #define ENDIAN_SWAP64(x)                        OSSwapInt64(x)
-       
-#else
-       #error file format undefined
-#endif
-
-
-#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
-       typedef uint64_t        macho_uintptr_t;
-       typedef int64_t         macho_intptr_t;
-#else
-       typedef uint32_t        macho_uintptr_t;
-       typedef int32_t         macho_intptr_t;
-#endif
-
-#if defined(MACHO_32_SAME_ENDIAN) 
-       #define ENDIAN_SWAP_POINTER(x)                          (x)
-#elif defined(MACHO_64_SAME_ENDIAN)
-       #define ENDIAN_SWAP_POINTER(x)                          (x)
-#elif defined(MACHO_32_OPPOSITE_ENDIAN) 
-       #define ENDIAN_SWAP_POINTER(x)                          OSSwapInt32(x)
-#elif defined(MACHO_64_OPPOSITE_ENDIAN)
-       #define ENDIAN_SWAP_POINTER(x)                          OSSwapInt64(x)
-#else
-       #error file format undefined
-#endif
-
-
-#undef mach_header 
-#undef mach_header_64 
-class macho_header {
-public:
-       uint32_t        magic() const;
-       void            set_magic(uint32_t);
-
-       cpu_type_t      cputype() const;
-       void            set_cputype(cpu_type_t);
-
-       cpu_subtype_t   cpusubtype() const;
-       void            set_cpusubtype(cpu_subtype_t);
-
-       uint32_t        filetype() const;
-       void            set_filetype(uint32_t);
-
-       uint32_t        ncmds() const;
-       void            set_ncmds(uint32_t);
-
-       uint32_t        sizeofcmds() const;
-       void            set_sizeofcmds(uint32_t);
-
-       uint32_t        flags() const;
-       void            set_flags(uint32_t);
-
-       void            set_reserved();
-        
-#if defined(MACHO_64_SAME_ENDIAN) 
-       enum { size = sizeof(mach_header_64) };
-       enum { magic_value = MH_MAGIC_64 };
-#elif defined(MACHO_64_OPPOSITE_ENDIAN)
-       enum { size = sizeof(mach_header_64) };
-       enum { magic_value = MH_MAGIC_64 };
-#elif defined(MACHO_32_SAME_ENDIAN)
-       enum { size = sizeof(mach_header) };
-       enum { magic_value = MH_MAGIC };
-#elif defined(MACHO_32_OPPOSITE_ENDIAN)
-       enum { size = sizeof(mach_header) };
-       enum { magic_value = MH_MAGIC };
-#endif
-
-private:
-#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
-       struct mach_header_64 content;
-#else
-       struct mach_header content;
-#endif
-};
-#define mach_header __my_bad
-#define mach_header_64 __my_bad
-
-inline  __attribute__((always_inline))
-uint32_t macho_header::magic() const {
-       return ENDIAN_READ32(content.magic);
-}
-
-inline  __attribute__((always_inline))
-void macho_header::set_magic(uint32_t _value) {
-       ENDIAN_WRITE32(content.magic, _value);
-}
-
-inline  __attribute__((always_inline))
-cpu_type_t macho_header::cputype() const {
-       return ENDIAN_READ32(content.cputype);
-}
-
-inline  __attribute__((always_inline))
-void macho_header::set_cputype(cpu_type_t _value) {
-       ENDIAN_WRITE32(content.cputype, _value);
-}
-
-inline  __attribute__((always_inline))
-cpu_subtype_t macho_header::cpusubtype() const {
-       return ENDIAN_READ32(content.cpusubtype);
-}
-
-inline  __attribute__((always_inline))
-void macho_header::set_cpusubtype(cpu_subtype_t _value) {
-       ENDIAN_WRITE32(content.cpusubtype, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_header::filetype() const {
-       return ENDIAN_READ32(content.filetype);
-}
-
-inline  __attribute__((always_inline))
-void macho_header::set_filetype(uint32_t _value) {
-       ENDIAN_WRITE32(content.filetype, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_header::ncmds() const {
-       return ENDIAN_READ32(content.ncmds);
-}
-
-inline  __attribute__((always_inline))
-void macho_header::set_ncmds(uint32_t _value) {
-       ENDIAN_WRITE32(content.ncmds, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_header::sizeofcmds() const {
-       return ENDIAN_READ32(content.sizeofcmds);
-}
-
-inline  __attribute__((always_inline))
-void macho_header::set_sizeofcmds(uint32_t _value) {
-       ENDIAN_WRITE32(content.sizeofcmds, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_header::flags() const {
-       return ENDIAN_READ32(content.flags);
-}
-
-inline  __attribute__((always_inline))
-void macho_header::set_flags(uint32_t _value) {
-       ENDIAN_WRITE32(content.flags, _value);
-}
-
-inline  __attribute__((always_inline))
-void macho_header::set_reserved() {
-#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
-       content.reserved = 0;
-#endif
-}
-
-
-#undef load_command
-class macho_load_command {
-public:
-       uint32_t        cmd() const;
-       void            set_cmd(uint32_t);
-
-       uint32_t        cmdsize() const;
-       void            set_cmdsize(uint32_t);
-       
-private:
-       struct load_command content;
-};
-
-inline  __attribute__((always_inline))
-uint32_t macho_load_command::cmd() const {
-       return ENDIAN_READ32(content.cmd);
-}
-
-inline  __attribute__((always_inline))
-void macho_load_command::set_cmd(uint32_t _value) {
-       ENDIAN_WRITE32(content.cmd, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_load_command::cmdsize() const {
-       return ENDIAN_READ32(content.cmdsize);
-}
-
-inline  __attribute__((always_inline))
-void macho_load_command::set_cmdsize(uint32_t _value) {
-       ENDIAN_WRITE32(content.cmdsize, _value);
-}
-#define load_command __my_bad
-
-
-#undef segment_command
-#undef segment_command_64
-class macho_segment_command {
-public:
-       uint32_t        cmd() const;
-       void            set_cmd(uint32_t);
-
-       uint32_t        cmdsize() const;
-       void            set_cmdsize(uint32_t);
-
-       const char*     segname() const;
-       void            set_segname(const char*);
-
-       uint64_t        vmaddr() const;
-       void            set_vmaddr(uint64_t);
-
-       uint64_t        vmsize() const;
-       void            set_vmsize(uint64_t);
-
-       uint64_t        fileoff() const;
-       void            set_fileoff(uint64_t);
-
-       uint64_t        filesize() const;
-       void            set_filesize(uint64_t);
-
-       vm_prot_t       maxprot() const;
-       void            set_maxprot(vm_prot_t);
-
-       vm_prot_t       initprot() const;
-       void            set_initprot(vm_prot_t);
-
-       uint32_t        nsects() const;
-       void            set_nsects(uint32_t);
-
-       uint32_t        flags() const;
-       void            set_flags(uint32_t);
-
-       enum { size = 
-#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
-       sizeof(segment_command_64) };
-#else
-       sizeof(segment_command) };
-#endif
-
-       enum { command = 
-#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
-               LC_SEGMENT_64
-#else
-               LC_SEGMENT
-#endif
-       };
-
-private:
-#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
-       struct segment_command_64 content;
-#else
-       struct segment_command content;
-#endif
-};
-#define segment_command __my_bad
-#define segment_command_64 __my_bad
-
-inline  __attribute__((always_inline))
-uint32_t macho_segment_command::cmd() const {
-       return ENDIAN_READ32(content.cmd);
-}
-
-inline  __attribute__((always_inline))
-void macho_segment_command::set_cmd(uint32_t _value) {
-       ENDIAN_WRITE32(content.cmd, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_segment_command::cmdsize() const {
-       return ENDIAN_READ32(content.cmdsize);
-}
-
-inline  __attribute__((always_inline))
-void macho_segment_command::set_cmdsize(uint32_t _value) {
-       ENDIAN_WRITE32(content.cmdsize, _value);
-}
-
-inline  __attribute__((always_inline))
-const char* macho_segment_command::segname() const {
-       return content.segname;
-}
-
-inline  __attribute__((always_inline))
-void macho_segment_command::set_segname(const char* _value) {
-       strncpy(content.segname, _value, 16);
-}
-
-inline  __attribute__((always_inline))
-uint64_t macho_segment_command::vmaddr() const {
-#if defined(ARCH_PPC64)
-       return ENDIAN_SWAP64(content.vmaddr);
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
-       return ENDIAN_READ32(content.vmaddr);
-#else
-       #error unknown architecture
-#endif
-}
-
-inline  __attribute__((always_inline))
-void macho_segment_command::set_vmaddr(uint64_t _value) {
-#if defined(ARCH_PPC64)
-       content.vmaddr = ENDIAN_SWAP64(_value);
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
-       ENDIAN_WRITE32(content.vmaddr, _value);
-#else
-       #error unknown architecture
-#endif
-}
-
-inline  __attribute__((always_inline))
-uint64_t macho_segment_command::vmsize() const {
-#if defined(ARCH_PPC64)
-       return ENDIAN_SWAP64(content.vmsize);
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
-       return ENDIAN_READ32(content.vmsize);
-#else
-       #error unknown architecture
-#endif
-}
-
-inline  __attribute__((always_inline))
-void macho_segment_command::set_vmsize(uint64_t _value) {
-#if defined(ARCH_PPC64)
-       content.vmsize = ENDIAN_SWAP64(_value);
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
-       ENDIAN_WRITE32(content.vmsize, _value);
-#else
-       #error unknown architecture
-#endif
-}
-
-inline  __attribute__((always_inline))
-uint64_t macho_segment_command::fileoff() const {
-#if defined(ARCH_PPC64)
-       return ENDIAN_SWAP64(content.fileoff);
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
-       return ENDIAN_READ32(content.fileoff);
-#else
-       #error unknown architecture
-#endif
-}
-
-inline  __attribute__((always_inline))
-void macho_segment_command::set_fileoff(uint64_t _value) {
-#if defined(ARCH_PPC64)
-       content.fileoff = ENDIAN_SWAP64(_value);
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
-       ENDIAN_WRITE32(content.fileoff, _value);
-#else
-       #error unknown architecture
-#endif
-}
-
-inline  __attribute__((always_inline))
-uint64_t macho_segment_command::filesize() const {
-#if defined(ARCH_PPC64)
-       return ENDIAN_SWAP64(content.filesize);
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
-       return ENDIAN_READ32(content.filesize);
-#else
-       #error unknown architecture
-#endif
-}
-
-inline  __attribute__((always_inline))
-void macho_segment_command::set_filesize(uint64_t _value) {
-#if defined(ARCH_PPC64)
-       content.filesize = ENDIAN_SWAP64(_value);
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
-       ENDIAN_WRITE32(content.filesize, _value);
-#else
-       #error unknown architecture
-#endif
-}
-
-inline  __attribute__((always_inline))
-vm_prot_t macho_segment_command::maxprot() const {
-       return ENDIAN_READ32(content.maxprot);
-}
-
-inline  __attribute__((always_inline))
-void macho_segment_command::set_maxprot(vm_prot_t _value) {
-       ENDIAN_WRITE32(content.maxprot, _value);
-}
-
-inline  __attribute__((always_inline))
-vm_prot_t macho_segment_command::initprot() const {
-       return ENDIAN_READ32(content.initprot);
-}
-
-inline  __attribute__((always_inline))
-void macho_segment_command::set_initprot(vm_prot_t _value) {
-       ENDIAN_WRITE32(content.initprot, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_segment_command::nsects() const {
-       return ENDIAN_READ32(content.nsects);
-}
-
-inline  __attribute__((always_inline))
-void macho_segment_command::set_nsects(uint32_t _value) {
-       ENDIAN_WRITE32(content.nsects, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_segment_command::flags() const {
-       return ENDIAN_READ32(content.flags);
-}
-
-inline  __attribute__((always_inline))
-void macho_segment_command::set_flags(uint32_t _value) {
-       ENDIAN_WRITE32(content.flags, _value);
-}
-
-#undef section
-#undef section_64
-class macho_section {
-public:
-       const char*     sectname() const;
-       void            set_sectname(const char*);
-
-       const char*     segname() const;
-       void            set_segname(const char*);
-
-       uint64_t        addr() const;
-       void            set_addr(uint64_t);
-
-       uint64_t        size() const;
-       void            set_size(uint64_t);
-
-       uint32_t        offset() const;
-       void            set_offset(uint32_t);
-
-       uint32_t        align() const;
-       void            set_align(uint32_t);
-
-       uint32_t        reloff() const;
-       void            set_reloff(uint32_t);
-
-       uint32_t        nreloc() const;
-       void            set_nreloc(uint32_t);
-
-       uint32_t        flags() const;
-       void            set_flags(uint32_t);
-
-       uint32_t        reserved1() const;
-       void            set_reserved1(uint32_t);
-
-       uint32_t        reserved2() const;
-       void            set_reserved2(uint32_t);
-
-       enum { content_size = 
-#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
-       sizeof(section_64) };
-#else
-       sizeof(section) };
-#endif
-
-private:
-#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
-       struct section_64 content;
-#else
-       struct section content;
-#endif
-};
-#define section __my_bad
-#define section_64 __my_bad
-
-inline  __attribute__((always_inline))
-const char* macho_section::sectname() const {
-       return content.sectname;
-}
-
-inline  __attribute__((always_inline))
-void macho_section::set_sectname(const char* _value) {
-       strncpy(content.sectname, _value, 16);
-}
-
-inline  __attribute__((always_inline))
-const char* macho_section::segname() const {
-       return content.segname;
-}
-
-inline  __attribute__((always_inline))
-void macho_section::set_segname(const char* _value) {
-       strncpy(content.segname, _value, 16);
-}
-
-inline  __attribute__((always_inline))
-uint64_t macho_section::addr() const {
-#if defined(ARCH_PPC64)
-       return ENDIAN_SWAP64(content.addr);
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
-       return ENDIAN_READ32(content.addr);
-#else
-       #error unknown architecture
-#endif
-}
-
-inline  __attribute__((always_inline))
-void macho_section::set_addr(uint64_t _value) {
-#if defined(ARCH_PPC64)
-       content.addr = ENDIAN_SWAP64(_value);
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
-       ENDIAN_WRITE32(content.addr, _value);
-#else
-       #error unknown architecture
-#endif
-}
-
-inline  __attribute__((always_inline))
-uint64_t macho_section::size() const {
-#if defined(ARCH_PPC64)
-       return ENDIAN_SWAP64(content.size);
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
-       return ENDIAN_READ32(content.size);
-#else
-       #error unknown architecture
-#endif
-}
-
-inline  __attribute__((always_inline))
-void macho_section::set_size(uint64_t _value) {
-#if defined(ARCH_PPC64)
-       content.size = ENDIAN_SWAP64(_value);
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
-       ENDIAN_WRITE32(content.size, _value);
-#else
-       #error unknown architecture
-#endif
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_section::offset() const {
-       return ENDIAN_READ32(content.offset);
-}
-
-inline  __attribute__((always_inline))
-void macho_section::set_offset(uint32_t _value) {
-       ENDIAN_WRITE32(content.offset, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_section::align() const {
-       return ENDIAN_READ32(content.align);
-}
-
-inline  __attribute__((always_inline))
-void macho_section::set_align(uint32_t _value) {
-       ENDIAN_WRITE32(content.align, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_section::reloff() const {
-       return ENDIAN_READ32(content.reloff);
-}
-
-inline  __attribute__((always_inline))
-void macho_section::set_reloff(uint32_t _value) {
-       ENDIAN_WRITE32(content.reloff, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_section::nreloc() const {
-       return ENDIAN_READ32(content.nreloc);
-}
-
-inline  __attribute__((always_inline))
-void macho_section::set_nreloc(uint32_t _value) {
-       ENDIAN_WRITE32(content.nreloc, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_section::flags() const {
-       return ENDIAN_READ32(content.flags);
-}
-
-inline  __attribute__((always_inline))
-void macho_section::set_flags(uint32_t _value) {
-       ENDIAN_WRITE32(content.flags, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_section::reserved1() const {
-       return ENDIAN_READ32(content.reserved1);
-}
-
-inline  __attribute__((always_inline))
-void macho_section::set_reserved1(uint32_t _value) {
-       ENDIAN_WRITE32(content.reserved1, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_section::reserved2() const {
-       return ENDIAN_READ32(content.reserved2);
-}
-
-inline  __attribute__((always_inline))
-void macho_section::set_reserved2(uint32_t _value) {
-       ENDIAN_WRITE32(content.reserved2, _value);
-}
-
-#undef dylib_command
-class macho_dylib_command {
-public:
-       uint32_t        cmd() const;
-       void            set_cmd(uint32_t);
-
-       uint32_t        cmdsize() const;
-       void            set_cmdsize(uint32_t);
-
-       const char*     name() const;
-       void            set_name_offset();
-
-       uint32_t        timestamp() const;
-       void            set_timestamp(uint32_t);
-
-       uint32_t        current_version() const;
-       void            set_current_version(uint32_t);
-
-       uint32_t        compatibility_version() const;
-       void            set_compatibility_version(uint32_t);
-
-       enum { name_offset = sizeof(struct dylib_command) };
-
-private:
-       struct dylib_command content;
-};
-#define dylib_command __my_bad
-
-inline  __attribute__((always_inline))
-uint32_t macho_dylib_command::cmd() const {
-       return ENDIAN_READ32(content.cmd);
-}
-
-inline  __attribute__((always_inline))
-void macho_dylib_command::set_cmd(uint32_t _value) {
-       ENDIAN_WRITE32(content.cmd, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_dylib_command::cmdsize() const {
-       return ENDIAN_READ32(content.cmdsize);
-}
-
-inline  __attribute__((always_inline))
-void macho_dylib_command::set_cmdsize(uint32_t _value) {
-       ENDIAN_WRITE32(content.cmdsize, _value);
-}
-
-inline  __attribute__((always_inline))
-const char* macho_dylib_command::name() const {
-       return (char*)(&content) + ENDIAN_READ32(content.dylib.name.offset);
-}
-
-inline  __attribute__((always_inline))
-void macho_dylib_command::set_name_offset() {
-       ENDIAN_WRITE32(content.dylib.name.offset, name_offset);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_dylib_command::timestamp() const {
-       return ENDIAN_READ32(content.dylib.timestamp);
-}
-
-inline  __attribute__((always_inline))
-void macho_dylib_command::set_timestamp(uint32_t _value) {
-       ENDIAN_WRITE32(content.dylib.timestamp, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_dylib_command::current_version() const {
-       return ENDIAN_READ32(content.dylib.current_version);
-}
-
-inline  __attribute__((always_inline))
-void macho_dylib_command::set_current_version(uint32_t _value) {
-       ENDIAN_WRITE32(content.dylib.current_version, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_dylib_command::compatibility_version() const {
-       return ENDIAN_READ32(content.dylib.compatibility_version);
-}
-
-inline  __attribute__((always_inline))
-void macho_dylib_command::set_compatibility_version(uint32_t _value) {
-       ENDIAN_WRITE32(content.dylib.compatibility_version, _value);
-}
-
-
-
-#undef dylinker_command
-class macho_dylinker_command {
-public:
-       uint32_t        cmd() const;
-       void            set_cmd(uint32_t);
-
-       uint32_t        cmdsize() const;
-       void            set_cmdsize(uint32_t);
-
-       void            set_name_offset();
-
-       enum { name_offset = sizeof(struct dylinker_command) };
-
-private:
-       struct dylinker_command content;
-};
-#define dylinker_command __my_bad
-
-inline  __attribute__((always_inline))
-uint32_t macho_dylinker_command::cmd() const {
-       return ENDIAN_READ32(content.cmd);
-}
-
-inline  __attribute__((always_inline))
-void macho_dylinker_command::set_cmd(uint32_t _value) {
-       ENDIAN_WRITE32(content.cmd, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_dylinker_command::cmdsize() const {
-       return ENDIAN_READ32(content.cmdsize);
-}
-
-inline  __attribute__((always_inline))
-void macho_dylinker_command::set_cmdsize(uint32_t _value) {
-       ENDIAN_WRITE32(content.cmdsize, _value);
-}
-
-inline  __attribute__((always_inline))
-void macho_dylinker_command::set_name_offset() {
-       ENDIAN_WRITE32(content.name.offset, name_offset);
-}
-
-
-
-#undef sub_framework_command 
-class macho_sub_framework_command {
-public:
-       uint32_t        cmd() const;
-       void            set_cmd(uint32_t);
-
-       uint32_t        cmdsize() const;
-       void            set_cmdsize(uint32_t);
-
-       const char*     name() const;
-       void            set_name_offset();
-
-       enum { name_offset = sizeof(struct sub_framework_command) };
-
-private:
-       struct sub_framework_command content;
-};
-#define sub_framework_command __my_bad
-
-inline  __attribute__((always_inline))
-uint32_t macho_sub_framework_command::cmd() const {
-       return ENDIAN_READ32(content.cmd);
-}
-
-inline  __attribute__((always_inline))
-void macho_sub_framework_command::set_cmd(uint32_t _value) {
-       ENDIAN_WRITE32(content.cmd, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_sub_framework_command::cmdsize() const {
-       return ENDIAN_READ32(content.cmdsize);
-}
-
-inline  __attribute__((always_inline))
-void macho_sub_framework_command::set_cmdsize(uint32_t _value) {
-       ENDIAN_WRITE32(content.cmdsize, _value);
-}
-
-inline  __attribute__((always_inline))
-const char* macho_sub_framework_command::name() const {
-       return (char*)(&content) + ENDIAN_READ32(content.umbrella.offset);
-}
-
-inline  __attribute__((always_inline))
-void macho_sub_framework_command::set_name_offset() {
-       ENDIAN_WRITE32(content.umbrella.offset, name_offset);
-}
-
-#undef sub_client_command 
-class macho_sub_client_command {
-public:
-       uint32_t        cmd() const;
-       void            set_cmd(uint32_t);
-
-       uint32_t        cmdsize() const;
-       void            set_cmdsize(uint32_t);
-
-       const char*     name() const;
-       void            set_name_offset();
-
-       enum { name_offset = sizeof(struct sub_client_command) };
-private:
-       struct sub_client_command content;
-};
-#define sub_client_command __my_bad
-
-inline  __attribute__((always_inline))
-uint32_t macho_sub_client_command::cmd() const {
-       return ENDIAN_READ32(content.cmd);
-}
-
-inline  __attribute__((always_inline))
-void macho_sub_client_command::set_cmd(uint32_t _value) {
-       ENDIAN_WRITE32(content.cmd, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_sub_client_command::cmdsize() const {
-       return ENDIAN_READ32(content.cmdsize);
-}
-
-inline  __attribute__((always_inline))
-void macho_sub_client_command::set_cmdsize(uint32_t _value) {
-       ENDIAN_WRITE32(content.cmdsize, _value);
-}
-
-inline  __attribute__((always_inline))
-const char* macho_sub_client_command::name() const {
-       return (char*)(&content) + ENDIAN_READ32(content.client.offset);
-}
-
-inline  __attribute__((always_inline))
-void macho_sub_client_command::set_name_offset() {
-       ENDIAN_WRITE32(content.client.offset, name_offset);
-}
-
-
-
-#undef sub_umbrella_command 
-class macho_sub_umbrella_command {
-public:
-       uint32_t        cmd() const;
-       void            set_cmd(uint32_t);
-
-       uint32_t        cmdsize() const;
-       void            set_cmdsize(uint32_t);
-
-       const char*     name() const;
-       void            set_name_offset();
-
-       enum { name_offset = sizeof(struct sub_umbrella_command) };
-private:
-       struct sub_umbrella_command content;
-};
-#define sub_umbrella_command __my_bad
-
-inline  __attribute__((always_inline))
-uint32_t macho_sub_umbrella_command::cmd() const {
-       return ENDIAN_READ32(content.cmd);
-}
-
-inline  __attribute__((always_inline))
-void macho_sub_umbrella_command::set_cmd(uint32_t _value) {
-       ENDIAN_WRITE32(content.cmd, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_sub_umbrella_command::cmdsize() const {
-       return ENDIAN_READ32(content.cmdsize);
-}
-
-inline  __attribute__((always_inline))
-void macho_sub_umbrella_command::set_cmdsize(uint32_t _value) {
-       ENDIAN_WRITE32(content.cmdsize, _value);
-}
-
-inline  __attribute__((always_inline))
-const char* macho_sub_umbrella_command::name() const {
-       return (char*)(&content) + ENDIAN_READ32(content.sub_umbrella.offset);
-}
-
-inline  __attribute__((always_inline))
-void macho_sub_umbrella_command::set_name_offset() {
-       ENDIAN_WRITE32(content.sub_umbrella.offset, name_offset);
-}
-
-
-
-
-#undef sub_library_command 
-class macho_sub_library_command {
-public:
-       uint32_t        cmd() const;
-       void            set_cmd(uint32_t);
-
-       uint32_t        cmdsize() const;
-       void            set_cmdsize(uint32_t);
-
-       const char*     name() const;
-       void            set_name_offset();
-
-       enum { name_offset = sizeof(struct sub_library_command) };
-private:
-       struct sub_library_command content;
-};
-#define sub_library_command __my_bad
-
-inline  __attribute__((always_inline))
-uint32_t macho_sub_library_command::cmd() const {
-       return ENDIAN_READ32(content.cmd);
-}
-
-inline  __attribute__((always_inline))
-void macho_sub_library_command::set_cmd(uint32_t _value) {
-       ENDIAN_WRITE32(content.cmd, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_sub_library_command::cmdsize() const {
-       return ENDIAN_READ32(content.cmdsize);
-}
-
-inline  __attribute__((always_inline))
-void macho_sub_library_command::set_cmdsize(uint32_t _value) {
-       ENDIAN_WRITE32(content.cmdsize, _value);
-}
-
-inline  __attribute__((always_inline))
-const char* macho_sub_library_command::name() const {
-       return (char*)(&content) + ENDIAN_READ32(content.sub_library.offset);
-}
-
-inline  __attribute__((always_inline))
-void macho_sub_library_command::set_name_offset() {
-       ENDIAN_WRITE32(content.sub_library.offset, name_offset);
-}
-
-
-
-#undef routines_command 
-#undef routines_command_64 
-class macho_routines_command {
-public:
-       uint32_t        cmd() const;
-       void            set_cmd(uint32_t);
-
-       uint32_t        cmdsize() const;
-       void            set_cmdsize(uint32_t);
-
-       uint64_t        init_address() const;
-       void            set_init_address(uint64_t);
-
-       uint64_t        init_module() const;
-       void            set_init_module(uint64_t);
-
-#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
-       enum { size = sizeof(struct routines_command_64) };
-       enum { command = LC_ROUTINES_64 };
-#else
-       enum { size = sizeof(struct routines_command) };
-       enum { command = LC_ROUTINES };
-#endif
-
-private:
-#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
-       struct routines_command_64 content;
-#else
-       struct routines_command content;
-#endif
-};
-#define routines_command __my_bad
-#define routines_command_64 __my_bad
-
-inline  __attribute__((always_inline))
-uint32_t macho_routines_command::cmd() const {
-       return ENDIAN_READ32(content.cmd);
-}
-
-inline  __attribute__((always_inline))
-void macho_routines_command::set_cmd(uint32_t _value) {
-       ENDIAN_WRITE32(content.cmd, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_routines_command::cmdsize() const {
-       return ENDIAN_READ32(content.cmdsize);
-}
-
-inline  __attribute__((always_inline))
-void macho_routines_command::set_cmdsize(uint32_t _value) {
-       ENDIAN_WRITE32(content.cmdsize, _value);
-}
-
-inline  __attribute__((always_inline))
-uint64_t macho_routines_command::init_address() const {
-#if defined(ARCH_PPC64)
-       return ENDIAN_SWAP64(content.init_address);
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
-       return ENDIAN_READ32(content.init_address);
-#else
-       #error unknown architecture
-#endif
-}
-
-inline  __attribute__((always_inline))
-void macho_routines_command::set_init_address(uint64_t _value) {
-#if defined(ARCH_PPC64)
-       content.init_address = ENDIAN_SWAP64(_value);
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
-       ENDIAN_WRITE32(content.init_address, _value);
-#else
-       #error unknown architecture
-#endif
-}
-
-inline  __attribute__((always_inline))
-uint64_t macho_routines_command::init_module() const {
-#if defined(ARCH_PPC64)
-       return ENDIAN_SWAP64(content.init_module);
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
-       return ENDIAN_READ32(content.init_module);
-#else
-       #error unknown architecture
-#endif
-}
-
-inline  __attribute__((always_inline))
-void macho_routines_command::set_init_module(uint64_t _value) {
-#if defined(ARCH_PPC64)
-       content.init_module = ENDIAN_SWAP64(_value);
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
-       ENDIAN_WRITE32(content.init_module, _value);
-#else
-       #error unknown architecture
-#endif
-}
-
-
-
-#undef symtab_command 
-class macho_symtab_command {
-public:
-       uint32_t        cmd() const;
-       void            set_cmd(uint32_t);
-
-       uint32_t        cmdsize() const;
-       void            set_cmdsize(uint32_t);
-
-       uint32_t        symoff() const;
-       void            set_symoff(uint32_t);
-
-       uint32_t        nsyms() const;
-       void            set_nsyms(uint32_t);
-
-       uint32_t        stroff() const;
-       void            set_stroff(uint32_t);
-
-       uint32_t        strsize() const;
-       void            set_strsize(uint32_t);
-       
-       enum { size = sizeof(struct symtab_command ) };
-       
-private:
-       struct symtab_command content;
-};
-#define symtab_command __my_bad
-
-
-inline  __attribute__((always_inline))
-uint32_t macho_symtab_command::cmd() const {
-       return ENDIAN_READ32(content.cmd);
-}
-
-inline  __attribute__((always_inline))
-void macho_symtab_command::set_cmd(uint32_t _value) {
-       ENDIAN_WRITE32(content.cmd, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_symtab_command::cmdsize() const {
-       return ENDIAN_READ32(content.cmdsize);
-}
-
-inline  __attribute__((always_inline))
-void macho_symtab_command::set_cmdsize(uint32_t _value) {
-       ENDIAN_WRITE32(content.cmdsize, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_symtab_command::symoff() const {
-       return ENDIAN_READ32(content.symoff);
-}
-
-inline  __attribute__((always_inline))
-void macho_symtab_command::set_symoff(uint32_t _value) {
-       ENDIAN_WRITE32(content.symoff, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_symtab_command::nsyms() const {
-       return ENDIAN_READ32(content.nsyms);
-}
-
-inline  __attribute__((always_inline))
-void macho_symtab_command::set_nsyms(uint32_t _value) {
-       ENDIAN_WRITE32(content.nsyms, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_symtab_command::stroff() const {
-       return ENDIAN_READ32(content.stroff);
-}
-
-inline  __attribute__((always_inline))
-void macho_symtab_command::set_stroff(uint32_t _value) {
-       ENDIAN_WRITE32(content.stroff, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_symtab_command::strsize() const {
-       return ENDIAN_READ32(content.strsize);
-}
-
-inline  __attribute__((always_inline))
-void macho_symtab_command::set_strsize(uint32_t _value) {
-       ENDIAN_WRITE32(content.strsize, _value);
-}
-
-
-#undef dysymtab_command 
-class macho_dysymtab_command {
-public:
-       uint32_t        cmd() const;
-       void            set_cmd(uint32_t);
-
-       uint32_t        cmdsize() const;
-       void            set_cmdsize(uint32_t);
-
-       uint32_t        ilocalsym() const;
-       void            set_ilocalsym(uint32_t);
-
-       uint32_t        nlocalsym() const;
-       void            set_nlocalsym(uint32_t);
-
-       uint32_t        iextdefsym() const;
-       void            set_iextdefsym(uint32_t);
-
-       uint32_t        nextdefsym() const;
-       void            set_nextdefsym(uint32_t);
-
-       uint32_t        iundefsym() const;
-       void            set_iundefsym(uint32_t);
-
-       uint32_t        nundefsym() const;
-       void            set_nundefsym(uint32_t);
-
-       uint32_t        tocoff() const;
-       void            set_tocoff(uint32_t);
-
-       uint32_t        ntoc() const;
-       void            set_ntoc(uint32_t);
-
-       uint32_t        modtaboff() const;
-       void            set_modtaboff(uint32_t);
-
-       uint32_t        nmodtab() const;
-       void            set_nmodtab(uint32_t);
-
-       uint32_t        extrefsymoff() const;
-       void            set_extrefsymoff(uint32_t);
-
-       uint32_t        nextrefsyms() const;
-       void            set_nextrefsyms(uint32_t);
-
-       uint32_t        indirectsymoff() const;
-       void            set_indirectsymoff(uint32_t);
-
-       uint32_t        nindirectsyms() const;
-       void            set_nindirectsyms(uint32_t);
-
-       uint32_t        extreloff() const;
-       void            set_extreloff(uint32_t);
-
-       uint32_t        nextrel() const;
-       void            set_nextrel(uint32_t);
-
-       uint32_t        locreloff() const;
-       void            set_locreloff(uint32_t);
-
-       uint32_t        nlocrel() const;
-       void            set_nlocrel(uint32_t);
-
-       enum { size = sizeof(struct dysymtab_command ) };
-private:
-       struct dysymtab_command content;
-};
-#define dysymtab_command __my_bad
-
-inline  __attribute__((always_inline))
-uint32_t macho_dysymtab_command::cmd() const {
-       return ENDIAN_READ32(content.cmd);
-}
-
-inline  __attribute__((always_inline))
-void macho_dysymtab_command::set_cmd(uint32_t _value) {
-       ENDIAN_WRITE32(content.cmd, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_dysymtab_command::cmdsize() const {
-       return ENDIAN_READ32(content.cmdsize);
-}
-
-inline  __attribute__((always_inline))
-void macho_dysymtab_command::set_cmdsize(uint32_t _value) {
-       ENDIAN_WRITE32(content.cmdsize, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_dysymtab_command::ilocalsym() const {
-       return ENDIAN_READ32(content.ilocalsym);
-}
-
-inline  __attribute__((always_inline))
-void macho_dysymtab_command::set_ilocalsym(uint32_t _value) {
-       ENDIAN_WRITE32(content.ilocalsym, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_dysymtab_command::nlocalsym() const {
-       return ENDIAN_READ32(content.nlocalsym);
-}
-
-inline  __attribute__((always_inline))
-void macho_dysymtab_command::set_nlocalsym(uint32_t _value) {
-       ENDIAN_WRITE32(content.nlocalsym, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_dysymtab_command::iextdefsym() const {
-       return ENDIAN_READ32(content.iextdefsym);
-}
-
-inline  __attribute__((always_inline))
-void macho_dysymtab_command::set_iextdefsym(uint32_t _value) {
-       ENDIAN_WRITE32(content.iextdefsym, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_dysymtab_command::nextdefsym() const {
-       return ENDIAN_READ32(content.nextdefsym);
-}
-
-inline  __attribute__((always_inline))
-void macho_dysymtab_command::set_nextdefsym(uint32_t _value) {
-       ENDIAN_WRITE32(content.nextdefsym, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_dysymtab_command::iundefsym() const {
-       return ENDIAN_READ32(content.iundefsym);
-}
-
-inline  __attribute__((always_inline))
-void macho_dysymtab_command::set_iundefsym(uint32_t _value) {
-       ENDIAN_WRITE32(content.iundefsym, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_dysymtab_command::nundefsym() const {
-       return ENDIAN_READ32(content.nundefsym);
-}
-
-inline  __attribute__((always_inline))
-void macho_dysymtab_command::set_nundefsym(uint32_t _value) {
-       ENDIAN_WRITE32(content.nundefsym, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_dysymtab_command::tocoff() const {
-       return ENDIAN_READ32(content.tocoff);
-}
-
-inline  __attribute__((always_inline))
-void macho_dysymtab_command::set_tocoff(uint32_t _value) {
-       ENDIAN_WRITE32(content.tocoff, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_dysymtab_command::ntoc() const {
-       return ENDIAN_READ32(content.ntoc);
-}
-
-inline  __attribute__((always_inline))
-void macho_dysymtab_command::set_ntoc(uint32_t _value) {
-       ENDIAN_WRITE32(content.ntoc, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_dysymtab_command::modtaboff() const {
-       return ENDIAN_READ32(content.modtaboff);
-}
-
-inline  __attribute__((always_inline))
-void macho_dysymtab_command::set_modtaboff(uint32_t _value) {
-       ENDIAN_WRITE32(content.modtaboff, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_dysymtab_command::nmodtab() const {
-       return ENDIAN_READ32(content.nmodtab);
-}
-
-inline  __attribute__((always_inline))
-void macho_dysymtab_command::set_nmodtab(uint32_t _value) {
-       ENDIAN_WRITE32(content.nmodtab, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_dysymtab_command::extrefsymoff() const {
-       return ENDIAN_READ32(content.extrefsymoff);
-}
-
-inline  __attribute__((always_inline))
-void macho_dysymtab_command::set_extrefsymoff(uint32_t _value) {
-       ENDIAN_WRITE32(content.extrefsymoff, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_dysymtab_command::nextrefsyms() const {
-       return ENDIAN_READ32(content.nextrefsyms);
-}
-
-inline  __attribute__((always_inline))
-void macho_dysymtab_command::set_nextrefsyms(uint32_t _value) {
-       ENDIAN_WRITE32(content.nextrefsyms, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_dysymtab_command::indirectsymoff() const {
-       return ENDIAN_READ32(content.indirectsymoff);
-}
-
-inline  __attribute__((always_inline))
-void macho_dysymtab_command::set_indirectsymoff(uint32_t _value) {
-       ENDIAN_WRITE32(content.indirectsymoff, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_dysymtab_command::nindirectsyms() const {
-       return ENDIAN_READ32(content.nindirectsyms);
-}
-
-inline  __attribute__((always_inline))
-void macho_dysymtab_command::set_nindirectsyms(uint32_t _value) {
-       ENDIAN_WRITE32(content.nindirectsyms, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_dysymtab_command::extreloff() const {
-       return ENDIAN_READ32(content.extreloff);
-}
-
-inline  __attribute__((always_inline))
-void macho_dysymtab_command::set_extreloff(uint32_t _value) {
-       ENDIAN_WRITE32(content.extreloff, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_dysymtab_command::nextrel() const {
-       return ENDIAN_READ32(content.nextrel);
-}
-
-inline  __attribute__((always_inline))
-void macho_dysymtab_command::set_nextrel(uint32_t _value) {
-       ENDIAN_WRITE32(content.nextrel, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_dysymtab_command::locreloff() const {
-       return ENDIAN_READ32(content.locreloff);
-}
-
-inline  __attribute__((always_inline))
-void macho_dysymtab_command::set_locreloff(uint32_t _value) {
-       ENDIAN_WRITE32(content.locreloff, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_dysymtab_command::nlocrel() const {
-       return ENDIAN_READ32(content.nlocrel);
-}
-
-inline  __attribute__((always_inline))
-void macho_dysymtab_command::set_nlocrel(uint32_t _value) {
-       ENDIAN_WRITE32(content.nlocrel, _value);
-}
-
-
-
-#undef twolevel_hints_command 
-class macho_twolevel_hints_command {
-public:
-       uint32_t        cmd() const;
-       void            set_cmd(uint32_t);
-
-       uint32_t        cmdsize() const;
-       void            set_cmdsize(uint32_t);
-
-       uint32_t        offset() const;
-       void            set_offset(uint32_t);
-
-       uint32_t        nhints() const;
-       void            set_nhints(uint32_t);
-
-private:
-       struct twolevel_hints_command content;
-};
-#define twolevel_hints_command __my_bad
-
-inline  __attribute__((always_inline))
-uint32_t macho_twolevel_hints_command::cmd() const {
-       return ENDIAN_READ32(content.cmd);
-}
-
-inline  __attribute__((always_inline))
-void macho_twolevel_hints_command::set_cmd(uint32_t _value) {
-       ENDIAN_WRITE32(content.cmd, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_twolevel_hints_command::cmdsize() const {
-       return ENDIAN_READ32(content.cmdsize);
-}
-
-inline  __attribute__((always_inline))
-void macho_twolevel_hints_command::set_cmdsize(uint32_t _value) {
-       ENDIAN_WRITE32(content.cmdsize, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_twolevel_hints_command::offset() const {
-       return ENDIAN_READ32(content.offset);
-}
-
-inline  __attribute__((always_inline))
-void macho_twolevel_hints_command::set_offset(uint32_t _value) {
-       ENDIAN_WRITE32(content.offset, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_twolevel_hints_command::nhints() const {
-       return ENDIAN_READ32(content.nhints);
-}
-
-inline  __attribute__((always_inline))
-void macho_twolevel_hints_command::set_nhints(uint32_t _value) {
-       ENDIAN_WRITE32(content.nhints, _value);
-}
-
-
-#undef thread_command
-class macho_thread_command {
-public:
-       uint32_t        cmd() const;
-       void            set_cmd(uint32_t);
-
-       uint32_t        cmdsize() const;
-       void            set_cmdsize(uint32_t);
-
-       uint32_t        flavor() const;
-       void            set_flavor(uint32_t);
-
-       uint32_t        count() const;
-       void            set_count(uint32_t);
-
-       uint32_t        threadState32(uint32_t index) const;
-       void            set_threadState32(uint32_t index, uint32_t value);
-
-       uint64_t        threadState64(uint32_t offset) const;
-       void            set_threadState64(uint32_t index, uint64_t value);
-
-       enum { size = sizeof(struct thread_command) + 8 };
-
-private:
-       struct thread_command   content;
-       uint32_t                                content_flavor;
-       uint32_t                                content_count;
-       uint32_t                                threadState[1];
-};
-#define thread_command __my_bad
-
-inline  __attribute__((always_inline))
-uint32_t macho_thread_command::cmd() const {
-       return ENDIAN_READ32(content.cmd);
-}
-
-inline  __attribute__((always_inline))
-void macho_thread_command::set_cmd(uint32_t _value) {
-       ENDIAN_WRITE32(content.cmd, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_thread_command::cmdsize() const {
-       return ENDIAN_READ32(content.cmdsize);
-}
-
-inline  __attribute__((always_inline))
-void macho_thread_command::set_cmdsize(uint32_t _value) {
-       ENDIAN_WRITE32(content.cmdsize, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_thread_command::flavor() const {
-       return ENDIAN_READ32(content_flavor);
-}
-
-inline  __attribute__((always_inline))
-void macho_thread_command::set_flavor(uint32_t _value) {
-       ENDIAN_WRITE32(content_flavor, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_thread_command::count() const {
-       return ENDIAN_READ32(content_count);
-}
-
-inline  __attribute__((always_inline))
-void macho_thread_command::set_count(uint32_t _value) {
-       ENDIAN_WRITE32(content_count, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_thread_command::threadState32(uint32_t index) const
-{
-       return ENDIAN_READ32(threadState[index]);
-}
-
-inline  __attribute__((always_inline))
-void macho_thread_command::set_threadState32(uint32_t index, uint32_t _value)
-{
-       ENDIAN_WRITE32(threadState[index], _value);
-}
-
-inline  __attribute__((always_inline))
-uint64_t macho_thread_command::threadState64(uint32_t index) const
-{
-       uint64_t temp = *((uint64_t*)(&threadState[index]));
-       return ENDIAN_SWAP64(temp);
-}
-
-inline  __attribute__((always_inline))
-void macho_thread_command::set_threadState64(uint32_t index, uint64_t _value)
-{
-       *((uint64_t*)(&threadState[index])) = ENDIAN_SWAP64(_value);
-}
-
-
-
-#undef nlist 
-#undef nlist_64
-class macho_nlist {
-public:
-       uint32_t        n_strx() const;
-       void            set_n_strx(uint32_t);
-
-       uint8_t         n_type() const;
-       void            set_n_type(uint8_t);
-
-       uint8_t         n_sect() const;
-       void            set_n_sect(uint8_t);
-
-       uint16_t        n_desc() const;
-       void            set_n_desc(uint16_t);
-
-       uint64_t        n_value() const;
-       void            set_n_value(uint64_t);
-
-       
-#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
-       enum { size = sizeof(struct nlist_64) };
-#else
-       enum { size = sizeof(struct nlist) };
-#endif
-
-private:
-#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
-       struct nlist_64 content;
-#else
-       struct nlist content;
-#endif
-};
-#define nlist __my_bad
-#define nlist_64 __my_bad
-
-inline  __attribute__((always_inline))
-uint32_t macho_nlist::n_strx() const {
-       return ENDIAN_READ32(content.n_un.n_strx);
-}
-
-inline  __attribute__((always_inline))
-void macho_nlist::set_n_strx(uint32_t _value) {
-       ENDIAN_WRITE32(content.n_un.n_strx, _value);
-}
-
-inline  __attribute__((always_inline))
-uint8_t macho_nlist::n_type() const {
-       return content.n_type;
-}
-
-inline  __attribute__((always_inline))
-void macho_nlist::set_n_type(uint8_t _value) {
-       content.n_type = _value;
-}
-
-inline  __attribute__((always_inline))
-uint8_t macho_nlist::n_sect() const {
-       return content.n_sect;
-}
-
-inline  __attribute__((always_inline))
-void macho_nlist::set_n_sect(uint8_t _value) {
-       content.n_sect = _value;
-}
-
-inline  __attribute__((always_inline))
-uint16_t macho_nlist::n_desc() const {
-       return ENDIAN_READ16(content.n_desc);
-}
-
-inline  __attribute__((always_inline))
-void macho_nlist::set_n_desc(uint16_t _value) {
-       ENDIAN_WRITE16(content.n_desc, _value);
-}
-
-inline  __attribute__((always_inline))
-uint64_t macho_nlist::n_value() const {
-#if defined(ARCH_PPC64)
-       return ENDIAN_SWAP64(content.n_value);
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
-       return ENDIAN_READ32(content.n_value);
-#else
-       #error unknown architecture
-#endif
-}
-
-inline  __attribute__((always_inline))
-void macho_nlist::set_n_value(uint64_t _value) {
-#if defined(ARCH_PPC64)
-       content.n_value = ENDIAN_SWAP64(_value);
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
-       ENDIAN_WRITE32(content.n_value, _value);
-#else
-       #error unknown architecture
-#endif
-}
-
-
-
-#undef relocation_info 
-class macho_relocation_info {
-public:
-       int32_t         r_address() const;
-       void            set_r_address(int32_t);
-
-       uint32_t        r_symbolnum() const;
-       void            set_r_symbolnum(uint32_t);
-
-       bool            r_pcrel() const;
-       void            set_r_pcrel(bool);
-
-       uint8_t         r_length() const;
-       void            set_r_length(uint8_t);
-
-       bool            r_extern() const;
-       void            set_r_extern(bool);
-
-       uint8_t         r_type() const;
-       void            set_r_type(uint8_t);
-
-       enum { size = sizeof(struct relocation_info) };
-#if defined(MACHO_64_SAME_ENDIAN) || defined(MACHO_64_OPPOSITE_ENDIAN)
-       enum { pointer_length = 3 };
-#else
-       enum { pointer_length = 2 };
-#endif
-       
-private:
-       struct relocation_info content;
-};
-#define relocation_info __my_bad
-
-
-inline  __attribute__((always_inline))
-int32_t macho_relocation_info::r_address() const {
-       return ENDIAN_READ32(content.r_address);
-}
-
-inline  __attribute__((always_inline))
-void macho_relocation_info::set_r_address(int32_t _value) {
-       ENDIAN_WRITE32(content.r_address, _value);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_relocation_info::r_symbolnum() const {
-       uint32_t temp = ENDIAN_READ32(((const uint32_t*)&content)[1]);
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
-       return (temp >> 8);
-#elif defined(ARCH_I386)
-       return temp & 0x00FFFFFF;
-#else
-       #error unknown architecture
-#endif
-}
-
-inline  __attribute__((always_inline))
-void macho_relocation_info::set_r_symbolnum(uint32_t _value) {
-       uint32_t temp = ENDIAN_READ32(((const uint32_t*)&content)[1]);
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
-       temp &= 0x000000FF;
-       temp |= ((_value & 0x00FFFFFF) << 8);
-#elif defined(ARCH_I386)
-       temp &= 0xFF000000;
-       temp |= (_value & 0x00FFFFFF);
-#else
-       #error unknown architecture
-#endif
-       ENDIAN_WRITE32(((uint32_t*)&content)[1], temp);
-}
-
-inline  __attribute__((always_inline))
-bool macho_relocation_info::r_pcrel() const {
-       uint32_t temp = ENDIAN_READ32(((const uint32_t*)&content)[1]);
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
-       return ((temp & 0x00000080) != 0);
-#elif defined(ARCH_I386)
-       return ((temp & 0x01000000) != 0);
-#else
-       #error unknown architecture
-#endif
-}
-
-inline  __attribute__((always_inline))
-void macho_relocation_info::set_r_pcrel(bool _value) {
-       uint32_t temp = ENDIAN_READ32(((const uint32_t*)&content)[1]);
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
-       temp &= 0xFFFFFF7F;
-       if ( _value )
-               temp |= 0x00000080;
-#elif defined(ARCH_I386)
-       temp &= 0xFEFFFFFF;
-       if ( _value )
-               temp |= 0x01000000;
-#else
-       #error unknown architecture
-#endif
-       ENDIAN_WRITE32(((uint32_t*)&content)[1], temp);
-}
-
-inline  __attribute__((always_inline))
-uint8_t macho_relocation_info::r_length() const {
-       uint32_t temp = ENDIAN_READ32(((const uint32_t*)&content)[1]);
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
-       return ((temp & 0x00000060) >> 5);
-#elif defined(ARCH_I386)
-       return ((temp & 0x06000000) >> 25);
-#else
-       #error unknown architecture
-#endif
-}
-
-inline  __attribute__((always_inline))
-void macho_relocation_info::set_r_length(uint8_t _value) {
-       uint32_t temp = ENDIAN_READ32(((const uint32_t*)&content)[1]);
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
-       temp &= 0xFFFFFF9F;
-       temp |= ((_value & 0x03) << 5);
-#elif defined(ARCH_I386)
-       temp &= 0xF9FFFFFF;
-       temp |= ((_value & 0x03) << 25);
-#else
-       #error unknown architecture
-#endif
-       ENDIAN_WRITE32(((uint32_t*)&content)[1], temp);
-}
-
-inline  __attribute__((always_inline))
-bool macho_relocation_info::r_extern() const {
-       uint32_t temp = ENDIAN_READ32(((const uint32_t*)&content)[1]);
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
-       return ((temp & 0x00000010) != 0);
-#elif defined(ARCH_I386)
-       return ((temp & 0x08000000) != 0);
-#else
-       #error unknown architecture
-#endif
-}
-
-inline  __attribute__((always_inline))
-void macho_relocation_info::set_r_extern(bool _value) {
-       uint32_t temp = ENDIAN_READ32(((const uint32_t*)&content)[1]);
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
-       temp &= 0xFFFFFFEF;
-       if ( _value )
-               temp |= 0x00000010;
-#elif defined(ARCH_I386)
-       temp &= 0xF7FFFFFF;
-       if ( _value )
-               temp |= 0x08000000;
-#else
-       #error unknown architecture
-#endif
-       ENDIAN_WRITE32(((uint32_t*)&content)[1], temp);
-}
-
-inline  __attribute__((always_inline))
-uint8_t macho_relocation_info::r_type() const {
-       uint32_t temp = ENDIAN_READ32(((const uint32_t*)&content)[1]);
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
-       return (temp & 0x0000000F);
-#elif defined(ARCH_I386)
-       return ((temp & 0xF0000000) >> 28);
-#else
-       #error unknown architecture
-#endif
-}
-
-inline  __attribute__((always_inline))
-void macho_relocation_info::set_r_type(uint8_t _value) {
-       uint32_t temp = ENDIAN_READ32(((const uint32_t*)&content)[1]);
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
-       temp &= 0xFFFFFFF0;
-       temp |= (_value & 0x0F);
-#elif defined(ARCH_I386)
-       temp &= 0x0FFFFFFF;
-       temp |= ((_value & 0x0F) << 28);
-#else
-       #error unknown architecture
-#endif
-       ENDIAN_WRITE32(((uint32_t*)&content)[1], temp);
-}
-
-
-
-#undef scattered_relocation_info 
-class macho_scattered_relocation_info {
-public:
-       bool            r_scattered() const;
-       void            set_r_scattered(bool);
-
-       bool            r_pcrel() const;
-       void            set_r_pcrel(bool);
-
-       uint8_t         r_length() const;
-       void            set_r_length(uint8_t);
-
-       uint8_t         r_type() const;
-       void            set_r_type(uint8_t);
-
-       uint32_t        r_address() const;
-       void            set_r_address(uint32_t);
-
-       int32_t         r_value() const;
-       void            set_r_value(int32_t);
-
-private:
-       struct scattered_relocation_info content;
-};
-#define scattered_relocation_info __my_bad
-
-inline  __attribute__((always_inline))
-bool macho_scattered_relocation_info::r_scattered() const {
-       uint32_t temp = *((const uint32_t*)&content);
-       temp = ENDIAN_READ32(temp);
-       return ((temp & 0x80000000) != 0);
-}
-
-inline  __attribute__((always_inline))
-void macho_scattered_relocation_info::set_r_scattered(bool _value) {
-       uint32_t temp = ENDIAN_READ32(*((const uint32_t*)&content));
-       if ( _value )
-               temp |= 0x80000000;
-       else
-               temp &= ~0x80000000;
-       ENDIAN_WRITE32(*((uint32_t*)&content), temp);
-}
-
-inline  __attribute__((always_inline))
-bool macho_scattered_relocation_info::r_pcrel() const {
-       uint32_t temp = *((const uint32_t*)&content);
-       temp = ENDIAN_READ32(temp);
-       return ((temp & 0x40000000) != 0);
-}
-
-inline  __attribute__((always_inline))
-void macho_scattered_relocation_info::set_r_pcrel(bool _value) {
-       uint32_t temp = ENDIAN_READ32(*((const uint32_t*)&content));
-       if ( _value )
-               temp |= 0x40000000;
-       else
-               temp &= ~0x40000000;
-       ENDIAN_WRITE32(*((uint32_t*)&content), temp);
-}
-
-inline  __attribute__((always_inline))
-uint8_t macho_scattered_relocation_info::r_length() const {
-       uint32_t temp = ENDIAN_READ32(*((const uint32_t*)&content));
-       return (temp >> 28) & 0x03;
-}
-
-inline  __attribute__((always_inline))
-void macho_scattered_relocation_info::set_r_length(uint8_t _value) {
-       uint32_t temp = ENDIAN_READ32(*((const uint32_t*)&content));
-       temp &= 0xCFFFFFFF;
-       temp |= ((_value & 0x03) << 28);
-       ENDIAN_WRITE32(*((uint32_t*)&content), temp);
-}
-
-inline  __attribute__((always_inline))
-uint8_t macho_scattered_relocation_info::r_type() const {
-       uint32_t temp = ENDIAN_READ32(*((const uint32_t*)&content));
-       return (temp >> 24) & 0x0F;
-}
-
-inline  __attribute__((always_inline))
-void macho_scattered_relocation_info::set_r_type(uint8_t _value) {
-       uint32_t temp = ENDIAN_READ32(*((const uint32_t*)&content));
-       temp &= 0xF0FFFFFF;
-       temp |= ((_value &0x0F) << 24);
-       ENDIAN_WRITE32(*((uint32_t*)&content), temp);
-}
-
-inline  __attribute__((always_inline))
-uint32_t macho_scattered_relocation_info::r_address() const {
-       uint32_t temp = ENDIAN_READ32(*((const uint32_t*)&content));
-       return temp & 0x00FFFFFF;
-}
-
-inline  __attribute__((always_inline))
-void macho_scattered_relocation_info::set_r_address(uint32_t _value) {
-       uint32_t temp = ENDIAN_READ32(*((const uint32_t*)&content));
-       _value &= 0x00FFFFFF;
-       temp &= 0xFF000000;
-       temp |= _value;
-       ENDIAN_WRITE32(*((uint32_t*)&content), temp);
-}
-
-inline  __attribute__((always_inline))
-int32_t macho_scattered_relocation_info::r_value() const {
-       return ENDIAN_READ32(content.r_value);
-}
-
-inline  __attribute__((always_inline))
-void macho_scattered_relocation_info::set_r_value(int32_t _value) {
-       ENDIAN_WRITE32(content.r_value, _value);
-}
-
-
-
-
diff --git a/src/MachOFileAbstraction.hpp b/src/MachOFileAbstraction.hpp
new file mode 100644 (file)
index 0000000..6110e80
--- /dev/null
@@ -0,0 +1,712 @@
+/* -*- 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 __MACH_O_FILE_ABSTRACTION__
+#define __MACH_O_FILE_ABSTRACTION__
+
+#include <mach-o/loader.h>
+#include <mach-o/nlist.h>
+#include <mach-o/reloc.h>
+#include <mach/machine.h>
+
+// suport older versions of mach-o/loader.h
+#ifndef LC_UUID
+#define LC_UUID                0x1b
+struct uuid_command {
+    uint32_t   cmd;            /* LC_UUID */
+    uint32_t   cmdsize;        /* sizeof(struct uuid_command) */
+    uint8_t    uuid[16];       /* the 128-bit uuid */
+};
+#endif
+
+
+#include "FileAbstraction.hpp"
+#include "Architectures.hpp"
+
+
+
+//
+// This abstraction layer makes every mach-o file look like a 64-bit mach-o file with native endianness
+//
+
+
+
+//
+// mach-o file header
+//
+template <typename P> struct macho_header_content {};
+template <> struct macho_header_content<Pointer32<BigEndian> >    { mach_header                fields; };
+template <> struct macho_header_content<Pointer64<BigEndian> >   { mach_header_64      fields; };
+template <> struct macho_header_content<Pointer32<LittleEndian> > { mach_header                fields; };
+template <> struct macho_header_content<Pointer64<LittleEndian> > { mach_header_64     fields; };
+
+template <typename P>
+class macho_header {
+public:
+       uint32_t                magic() const                                   INLINE { return E::get32(header.fields.magic); }
+       void                    set_magic(uint32_t value)               INLINE { E::set32(header.fields.magic, value); }
+
+       uint32_t                cputype() const                                 INLINE { return E::get32(header.fields.cputype); }
+       void                    set_cputype(uint32_t value)             INLINE { E::set32((uint32_t&)header.fields.cputype, value); }
+
+       uint32_t                cpusubtype() const                              INLINE { return E::get32(header.fields.cpusubtype); }
+       void                    set_cpusubtype(uint32_t value)  INLINE { E::set32((uint32_t&)header.fields.cpusubtype, value); }
+
+       uint32_t                filetype() const                                INLINE { return E::get32(header.fields.filetype); }
+       void                    set_filetype(uint32_t value)    INLINE { E::set32(header.fields.filetype, value); }
+
+       uint32_t                ncmds() const                                   INLINE { return E::get32(header.fields.ncmds); }
+       void                    set_ncmds(uint32_t value)               INLINE { E::set32(header.fields.ncmds, value); }
+
+       uint32_t                sizeofcmds() const                              INLINE { return E::get32(header.fields.sizeofcmds); }
+       void                    set_sizeofcmds(uint32_t value)  INLINE { E::set32(header.fields.sizeofcmds, value); }
+
+       uint32_t                flags() const                                   INLINE { return E::get32(header.fields.flags); }
+       void                    set_flags(uint32_t value)               INLINE { E::set32(header.fields.flags, value); }
+
+       uint32_t                reserved() const                                INLINE { return E::get32(header.fields.reserved); }
+       void                    set_reserved(uint32_t value)    INLINE { E::set32(header.fields.reserved, value); }
+
+       typedef typename P::E           E;
+private:
+       macho_header_content<P> header;
+};
+
+
+//
+// mach-o load command
+//
+template <typename P>
+class macho_load_command {
+public:
+       uint32_t                cmd() const                                             INLINE { return E::get32(command.cmd); }
+       void                    set_cmd(uint32_t value)                 INLINE { E::set32(command.cmd, value); }
+
+       uint32_t                cmdsize() const                                 INLINE { return E::get32(command.cmdsize); }
+       void                    set_cmdsize(uint32_t value)             INLINE { E::set32(command.cmdsize, value); }
+
+       typedef typename P::E           E;
+private:
+       load_command    command;
+};
+
+
+//
+// mach-o segment load command
+//
+template <typename P> struct macho_segment_content {};
+template <> struct macho_segment_content<Pointer32<BigEndian> >    { segment_command   fields; enum { CMD = LC_SEGMENT         }; };
+template <> struct macho_segment_content<Pointer64<BigEndian> >           { segment_command_64 fields; enum { CMD = LC_SEGMENT_64      }; };
+template <> struct macho_segment_content<Pointer32<LittleEndian> > { segment_command   fields; enum { CMD = LC_SEGMENT         }; };
+template <> struct macho_segment_content<Pointer64<LittleEndian> > { segment_command_64        fields; enum { CMD = LC_SEGMENT_64      }; };
+
+template <typename P>
+class macho_segment_command {
+public:
+       uint32_t                cmd() const                                             INLINE { return E::get32(segment.fields.cmd); }
+       void                    set_cmd(uint32_t value)                 INLINE { E::set32(segment.fields.cmd, value); }
+
+       uint32_t                cmdsize() const                                 INLINE { return E::get32(segment.fields.cmdsize); }
+       void                    set_cmdsize(uint32_t value)             INLINE { E::set32(segment.fields.cmdsize, value); }
+
+       const char*             segname() const                                 INLINE { return segment.fields.segname; }
+       void                    set_segname(const char* value)  INLINE { memcpy(&segment.fields.segname, value, 16); }
+       
+       uint64_t                vmaddr() const                                  INLINE { return P::getP(segment.fields.vmaddr); }
+       void                    set_vmaddr(uint64_t value)              INLINE { P::setP(segment.fields.vmaddr, value); }
+
+       uint64_t                vmsize() const                                  INLINE { return P::getP(segment.fields.vmsize); }
+       void                    set_vmsize(uint64_t value)              INLINE { P::setP(segment.fields.vmsize, value); }
+
+       uint64_t                fileoff() const                                 INLINE { return P::getP(segment.fields.fileoff); }
+       void                    set_fileoff(uint64_t value)             INLINE { P::setP(segment.fields.fileoff, value); }
+
+       uint64_t                filesize() const                                INLINE { return P::getP(segment.fields.filesize); }
+       void                    set_filesize(uint64_t value)    INLINE { P::setP(segment.fields.filesize, value); }
+
+       uint32_t                maxprot() const                                 INLINE { return E::get32(segment.fields.maxprot); }
+       void                    set_maxprot(uint32_t value)             INLINE { E::set32((uint32_t&)segment.fields.maxprot, value); }
+
+       uint32_t                initprot() const                                INLINE { return E::get32(segment.fields.initprot); }
+       void                    set_initprot(uint32_t value)    INLINE { E::set32((uint32_t&)segment.fields.initprot, value); }
+
+       uint32_t                nsects() const                                  INLINE { return E::get32(segment.fields.nsects); }
+       void                    set_nsects(uint32_t value)              INLINE { E::set32(segment.fields.nsects, value); }
+
+       uint32_t                flags() const                                   INLINE { return E::get32(segment.fields.flags); }
+       void                    set_flags(uint32_t value)               INLINE { E::set32(segment.fields.flags, value); }
+
+       enum {
+               CMD = macho_segment_content<P>::CMD
+       };
+
+       typedef typename P::E           E;
+private:
+       macho_segment_content<P>        segment;
+};
+
+
+//
+// mach-o section 
+//
+template <typename P> struct macho_section_content {};
+template <> struct macho_section_content<Pointer32<BigEndian> >    { section   fields; };
+template <> struct macho_section_content<Pointer64<BigEndian> >           { section_64 fields; };
+template <> struct macho_section_content<Pointer32<LittleEndian> > { section   fields; };
+template <> struct macho_section_content<Pointer64<LittleEndian> > { section_64        fields; };
+
+template <typename P>
+class macho_section {
+public:
+       const char*             sectname() const                                INLINE { return section.fields.sectname; }
+       void                    set_sectname(const char* value) INLINE { memcpy(&section.fields.sectname, value, 16); }
+       
+       const char*             segname() const                                 INLINE { return section.fields.segname; }
+       void                    set_segname(const char* value)  INLINE { memcpy(&section.fields.segname, value, 16); }
+       
+       uint64_t                addr() const                                    INLINE { return P::getP(section.fields.addr); }
+       void                    set_addr(uint64_t value)                INLINE { P::setP(section.fields.addr, value); }
+
+       uint64_t                size() const                                    INLINE { return P::getP(section.fields.size); }
+       void                    set_size(uint64_t value)                INLINE { P::setP(section.fields.size, value); }
+
+       uint32_t                offset() const                                  INLINE { return E::get32(section.fields.offset); }
+       void                    set_offset(uint32_t value)              INLINE { E::set32(section.fields.offset, value); }
+
+       uint32_t                align() const                                   INLINE { return E::get32(section.fields.align); }
+       void                    set_align(uint32_t value)               INLINE { E::set32(section.fields.align, value); }
+
+       uint32_t                reloff() const                                  INLINE { return E::get32(section.fields.reloff); }
+       void                    set_reloff(uint32_t value)              INLINE { E::set32(section.fields.reloff, value); }
+
+       uint32_t                nreloc() const                                  INLINE { return E::get32(section.fields.nreloc); }
+       void                    set_nreloc(uint32_t value)              INLINE { E::set32(section.fields.nreloc, value); }
+
+       uint32_t                flags() const                                   INLINE { return E::get32(section.fields.flags); }
+       void                    set_flags(uint32_t value)               INLINE { E::set32(section.fields.flags, value); }
+
+       uint32_t                reserved1() const                               INLINE { return E::get32(section.fields.reserved1); }
+       void                    set_reserved1(uint32_t value)   INLINE { E::set32(section.fields.reserved1, value); }
+
+       uint32_t                reserved2() const                               INLINE { return E::get32(section.fields.reserved2); }
+       void                    set_reserved2(uint32_t value)   INLINE { E::set32(section.fields.reserved2, value); }
+
+       typedef typename P::E           E;
+private:
+       macho_section_content<P>        section;
+};
+
+
+//
+// mach-o dylib load command
+//
+template <typename P>
+class macho_dylib_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                name_offset() const                                                     INLINE { return E::get32(fields.dylib.name.offset); }
+       void                    set_name_offset(uint32_t value)                         INLINE { E::set32(fields.dylib.name.offset, value);  }
+       
+       uint32_t                timestamp() const                                                       INLINE { return E::get32(fields.dylib.timestamp); }
+       void                    set_timestamp(uint32_t value)                           INLINE { E::set32(fields.dylib.timestamp, value); }
+
+       uint32_t                current_version() const                                         INLINE { return E::get32(fields.dylib.current_version); }
+       void                    set_current_version(uint32_t value)                     INLINE { E::set32(fields.dylib.current_version, value); }
+
+       uint32_t                compatibility_version() const                           INLINE { return E::get32(fields.dylib.compatibility_version); }
+       void                    set_compatibility_version(uint32_t value)       INLINE { E::set32(fields.dylib.compatibility_version, value); }
+
+       const char*             name() const                                                            INLINE { return (const char*)&fields + name_offset(); }
+       void                    set_name_offset()                                                       INLINE { set_name_offset(sizeof(fields)); }
+       
+       typedef typename P::E           E;
+private:
+       dylib_command   fields;
+};
+
+
+//
+// mach-o dylinker load command
+//
+template <typename P>
+class macho_dylinker_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                name_offset() const                                     INLINE { return E::get32(fields.name.offset); }
+       void                    set_name_offset(uint32_t value)         INLINE { E::set32(fields.name.offset, value);  }
+       
+       const char*             name() const                                            INLINE { return (const char*)&fields + name_offset(); }
+       void                    set_name_offset()                                       INLINE { set_name_offset(sizeof(fields)); }
+       
+       typedef typename P::E           E;
+private:
+       dylinker_command        fields;
+};
+
+
+//
+// mach-o sub_framework load command
+//
+template <typename P>
+class macho_sub_framework_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                umbrella_offset() const                         INLINE { return E::get32(fields.umbrella.offset); }
+       void                    set_umbrella_offset(uint32_t value)     INLINE { E::set32(fields.umbrella.offset, value);  }
+       
+       const char*             umbrella() const                                        INLINE { return (const char*)&fields + umbrella_offset(); }
+       void                    set_umbrella_offset()                           INLINE { set_umbrella_offset(sizeof(fields)); }
+               
+       typedef typename P::E           E;
+private:
+       sub_framework_command   fields;
+};
+
+
+//
+// mach-o sub_client load command
+//
+template <typename P>
+class macho_sub_client_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                client_offset() const                           INLINE { return E::get32(fields.client.offset); }
+       void                    set_client_offset(uint32_t value)       INLINE { E::set32(fields.client.offset, value);  }
+       
+       const char*             client() const                                          INLINE { return (const char*)&fields + client_offset(); }
+       void                    set_client_offset()                                     INLINE { set_client_offset(sizeof(fields)); }
+               
+       typedef typename P::E           E;
+private:
+       sub_client_command      fields;
+};
+
+
+//
+// mach-o sub_umbrella load command
+//
+template <typename P>
+class macho_sub_umbrella_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                sub_umbrella_offset() const                             INLINE { return E::get32(fields.sub_umbrella.offset); }
+       void                    set_sub_umbrella_offset(uint32_t value) INLINE { E::set32(fields.sub_umbrella.offset, value);  }
+       
+       const char*             sub_umbrella() const                                    INLINE { return (const char*)&fields + sub_umbrella_offset(); }
+       void                    set_sub_umbrella_offset()                               INLINE { set_sub_umbrella_offset(sizeof(fields)); }
+               
+       typedef typename P::E           E;
+private:
+       sub_umbrella_command    fields;
+};
+
+
+//
+// mach-o sub_library load command
+//
+template <typename P>
+class macho_sub_library_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                sub_library_offset() const                              INLINE { return E::get32(fields.sub_library.offset); }
+       void                    set_sub_library_offset(uint32_t value)  INLINE { E::set32(fields.sub_library.offset, value);  }
+       
+       const char*             sub_library() const                                             INLINE { return (const char*)&fields + sub_library_offset(); }
+       void                    set_sub_library_offset()                                INLINE { set_sub_library_offset(sizeof(fields)); }
+               
+       typedef typename P::E           E;
+private:
+       sub_library_command     fields;
+};
+
+
+//
+// mach-o uuid load command
+//
+template <typename P>
+class macho_uuid_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); }
+
+       const uint8_t*  uuid() const                                                    INLINE { return fields.uuid; }
+       void                    set_uuid(uint8_t uuid[16])                              INLINE { memcpy(&fields.uuid, uuid, 16); }
+                       
+       typedef typename P::E           E;
+private:
+       uuid_command    fields;
+};
+
+
+//
+// mach-o routines load command
+//
+template <typename P> struct macho_routines_content {};
+template <> struct macho_routines_content<Pointer32<BigEndian> >    { routines_command         fields; enum { CMD = LC_ROUTINES        }; };
+template <> struct macho_routines_content<Pointer64<BigEndian> >       { routines_command_64   fields; enum { CMD = LC_ROUTINES_64     }; };
+template <> struct macho_routines_content<Pointer32<LittleEndian> > { routines_command         fields; enum { CMD = LC_ROUTINES        }; };
+template <> struct macho_routines_content<Pointer64<LittleEndian> > { routines_command_64      fields; enum { CMD = LC_ROUTINES_64     }; };
+
+template <typename P>
+class macho_routines_command {
+public:
+       uint32_t                cmd() const                                                     INLINE { return E::get32(routines.fields.cmd); }
+       void                    set_cmd(uint32_t value)                         INLINE { E::set32(routines.fields.cmd, value); }
+
+       uint32_t                cmdsize() const                                         INLINE { return E::get32(routines.fields.cmdsize); }
+       void                    set_cmdsize(uint32_t value)                     INLINE { E::set32(routines.fields.cmdsize, value); }
+
+       uint64_t                init_address() const                            INLINE { return P::getP(routines.fields.init_address); }
+       void                    set_init_address(uint64_t value)        INLINE { P::setP(routines.fields.init_address, value); }
+
+       uint64_t                init_module() const                                     INLINE { return P::getP(routines.fields.init_module); }
+       void                    set_init_module(uint64_t value)         INLINE { P::setP(routines.fields.init_module, value); }
+
+       uint64_t                reserved1() const                                       INLINE { return P::getP(routines.fields.reserved1); }
+       void                    set_reserved1(uint64_t value)           INLINE { P::setP(routines.fields.reserved1, value); }
+       
+       uint64_t                reserved2() const                                       INLINE { return P::getP(routines.fields.reserved2); }
+       void                    set_reserved2(uint64_t value)           INLINE { P::setP(routines.fields.reserved2, value); }
+       
+       uint64_t                reserved3() const                                       INLINE { return P::getP(routines.fields.reserved3); }
+       void                    set_reserved3(uint64_t value)           INLINE { P::setP(routines.fields.reserved3, value); }
+       
+       uint64_t                reserved4() const                                       INLINE { return P::getP(routines.fields.reserved4); }
+       void                    set_reserved4(uint64_t value)           INLINE { P::setP(routines.fields.reserved4, value); }
+       
+       uint64_t                reserved5() const                                       INLINE { return P::getP(routines.fields.reserved5); }
+       void                    set_reserved5(uint64_t value)           INLINE { P::setP(routines.fields.reserved5, value); }
+       
+       uint64_t                reserved6() const                                       INLINE { return P::getP(routines.fields.reserved6); }
+       void                    set_reserved6(uint64_t value)           INLINE { P::setP(routines.fields.reserved6, value); }
+       
+       typedef typename P::E           E;
+       enum {
+               CMD = macho_routines_content<P>::CMD
+       };
+private:
+       macho_routines_content<P>       routines;
+};
+
+
+//
+// mach-o symbol table load command
+//
+template <typename P>
+class macho_symtab_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                symoff() const                          INLINE { return E::get32(fields.symoff); }
+       void                    set_symoff(uint32_t value)      INLINE { E::set32(fields.symoff, value);  }
+       
+       uint32_t                nsyms() const                           INLINE { return E::get32(fields.nsyms); }
+       void                    set_nsyms(uint32_t value)       INLINE { E::set32(fields.nsyms, value);  }
+       
+       uint32_t                stroff() const                          INLINE { return E::get32(fields.stroff); }
+       void                    set_stroff(uint32_t value)      INLINE { E::set32(fields.stroff, value);  }
+       
+       uint32_t                strsize() const                         INLINE { return E::get32(fields.strsize); }
+       void                    set_strsize(uint32_t value)     INLINE { E::set32(fields.strsize, value);  }
+       
+       
+       typedef typename P::E           E;
+private:
+       symtab_command  fields;
+};
+
+
+//
+// mach-o dynamic symbol table load command
+//
+template <typename P>
+class macho_dysymtab_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                ilocalsym() const                                       INLINE { return E::get32(fields.ilocalsym); }
+       void                    set_ilocalsym(uint32_t value)           INLINE { E::set32(fields.ilocalsym, value);  }
+       
+       uint32_t                nlocalsym() const                                       INLINE { return E::get32(fields.nlocalsym); }
+       void                    set_nlocalsym(uint32_t value)           INLINE { E::set32(fields.nlocalsym, value);  }
+       
+       uint32_t                iextdefsym() const                                      INLINE { return E::get32(fields.iextdefsym); }
+       void                    set_iextdefsym(uint32_t value)          INLINE { E::set32(fields.iextdefsym, value);  }
+       
+       uint32_t                nextdefsym() const                                      INLINE { return E::get32(fields.nextdefsym); }
+       void                    set_nextdefsym(uint32_t value)          INLINE { E::set32(fields.nextdefsym, value);  }
+       
+       uint32_t                iundefsym() const                                       INLINE { return E::get32(fields.iundefsym); }
+       void                    set_iundefsym(uint32_t value)           INLINE { E::set32(fields.iundefsym, value);  }
+       
+       uint32_t                nundefsym() const                                       INLINE { return E::get32(fields.nundefsym); }
+       void                    set_nundefsym(uint32_t value)           INLINE { E::set32(fields.nundefsym, value);  }
+       
+       uint32_t                tocoff() const                                          INLINE { return E::get32(fields.tocoff); }
+       void                    set_tocoff(uint32_t value)                      INLINE { E::set32(fields.tocoff, value);  }
+       
+       uint32_t                ntoc() const                                            INLINE { return E::get32(fields.ntoc); }
+       void                    set_ntoc(uint32_t value)                        INLINE { E::set32(fields.ntoc, value);  }
+       
+       uint32_t                modtaboff() const                                       INLINE { return E::get32(fields.modtaboff); }
+       void                    set_modtaboff(uint32_t value)           INLINE { E::set32(fields.modtaboff, value);  }
+       
+       uint32_t                nmodtab() const                                         INLINE { return E::get32(fields.nmodtab); }
+       void                    set_nmodtab(uint32_t value)                     INLINE { E::set32(fields.nmodtab, value);  }
+       
+       uint32_t                extrefsymoff() const                            INLINE { return E::get32(fields.extrefsymoff); }
+       void                    set_extrefsymoff(uint32_t value)        INLINE { E::set32(fields.extrefsymoff, value);  }
+       
+       uint32_t                nextrefsyms() const                                     INLINE { return E::get32(fields.nextrefsyms); }
+       void                    set_nextrefsyms(uint32_t value)         INLINE { E::set32(fields.nextrefsyms, value);  }
+       
+       uint32_t                indirectsymoff() const                          INLINE { return E::get32(fields.indirectsymoff); }
+       void                    set_indirectsymoff(uint32_t value)      INLINE { E::set32(fields.indirectsymoff, value);  }
+       
+       uint32_t                nindirectsyms() const                           INLINE { return E::get32(fields.nindirectsyms); }
+       void                    set_nindirectsyms(uint32_t value)       INLINE { E::set32(fields.nindirectsyms, value);  }
+       
+       uint32_t                extreloff() const                                       INLINE { return E::get32(fields.extreloff); }
+       void                    set_extreloff(uint32_t value)           INLINE { E::set32(fields.extreloff, value);  }
+       
+       uint32_t                nextrel() const                                         INLINE { return E::get32(fields.nextrel); }
+       void                    set_nextrel(uint32_t value)                     INLINE { E::set32(fields.nextrel, value);  }
+       
+       uint32_t                locreloff() const                                       INLINE { return E::get32(fields.locreloff); }
+       void                    set_locreloff(uint32_t value)           INLINE { E::set32(fields.locreloff, value);  }
+       
+       uint32_t                nlocrel() const                                         INLINE { return E::get32(fields.nlocrel); }
+       void                    set_nlocrel(uint32_t value)                     INLINE { E::set32(fields.nlocrel, value);  }
+       
+       typedef typename P::E           E;
+private:
+       dysymtab_command        fields;
+};
+
+
+//
+// mach-o two-level hints load command
+//
+template <typename P>
+class macho_twolevel_hints_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                offset() const                          INLINE { return E::get32(fields.offset); }
+       void                    set_offset(uint32_t value)      INLINE { E::set32(fields.offset, value);  }
+       
+       uint32_t                nhints() const                          INLINE { return E::get32(fields.nhints); }
+       void                    set_nhints(uint32_t value)      INLINE { E::set32(fields.nhints, value);  }
+       
+       typedef typename P::E           E;
+private:
+       twolevel_hints_command  fields;
+};
+
+
+//
+// mach-o threads load command
+//
+template <typename P>
+class macho_thread_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                flavor() const                                                                          INLINE { return E::get32(fields_flavor); }
+       void                    set_flavor(uint32_t value)                                                      INLINE { E::set32(fields_flavor, value);  }
+       
+       uint32_t                count() const                                                                           INLINE { return E::get32(fields_count); }
+       void                    set_count(uint32_t value)                                                       INLINE { E::set32(fields_count, value);  }
+       
+       uint64_t                thread_register(uint32_t index) const                           INLINE { return P::getP(thread_registers[index]); }
+       void                    set_thread_register(uint32_t index, uint64_t value)     INLINE { P::setP(thread_registers[index], value); }
+       
+       typedef typename P::E           E;
+       typedef typename P::uint_t      pint_t;
+private:
+       struct thread_command   fields;
+       uint32_t                                fields_flavor;
+       uint32_t                                fields_count;
+       pint_t                                  thread_registers[1];
+};
+
+
+
+
+//
+// mach-o symbol table entry 
+//
+template <typename P> struct macho_nlist_content {};
+template <> struct macho_nlist_content<Pointer32<BigEndian> >    { struct nlist                fields; };
+template <> struct macho_nlist_content<Pointer64<BigEndian> >   { struct nlist_64      fields; };
+template <> struct macho_nlist_content<Pointer32<LittleEndian> > { struct nlist                fields; };
+template <> struct macho_nlist_content<Pointer64<LittleEndian> > { struct nlist_64     fields; };
+
+template <typename P>
+class macho_nlist {
+public:
+       uint32_t                n_strx() const                                  INLINE { return E::get32(entry.fields.n_un.n_strx); }
+       void                    set_n_strx(uint32_t value)              INLINE { E::set32((uint32_t&)entry.fields.n_un.n_strx, value); }
+
+       uint8_t                 n_type() const                                  INLINE { return entry.fields.n_type; }
+       void                    set_n_type(uint8_t value)               INLINE { entry.fields.n_type = value; }
+
+       uint8_t                 n_sect() const                                  INLINE { return entry.fields.n_sect; }
+       void                    set_n_sect(uint8_t value)               INLINE { entry.fields.n_sect = value; }
+
+       uint16_t                n_desc() const                                  INLINE { return E::get16(entry.fields.n_desc); }
+       void                    set_n_desc(uint16_t value)              INLINE { E::set16((uint16_t&)entry.fields.n_desc, value); }
+
+       uint64_t                n_value() const                                 INLINE { return P::getP(entry.fields.n_value); }
+       void                    set_n_value(uint64_t value)             INLINE { P::setP(entry.fields.n_value, value); }
+
+       typedef typename P::E           E;
+private:
+       macho_nlist_content<P>  entry;
+};
+
+
+
+//
+// mach-o relocation info
+//
+template <typename P>
+class macho_relocation_info {
+public:
+       uint32_t                r_address() const                               INLINE { return E::get32(address); }
+       void                    set_r_address(uint32_t value)   INLINE { E::set32(address, value); }
+
+       uint32_t                r_symbolnum() const                             INLINE { return E::getBits(other, 0, 24); }
+       void                    set_r_symbolnum(uint32_t value) INLINE { E::setBits(other, value, 0, 24); }
+
+       bool                    r_pcrel() const                                 INLINE { return E::getBits(other, 24, 1); }
+       void                    set_r_pcrel(bool value)                 INLINE { E::setBits(other, value, 24, 1); }     
+       
+       uint8_t                 r_length() const                                INLINE { return E::getBits(other, 25, 2); }
+       void                    set_r_length(uint8_t value)             INLINE { E::setBits(other, value, 25, 2); }
+       
+       bool                    r_extern() const                                INLINE { return E::getBits(other, 27, 1); }
+       void                    set_r_extern(bool value)                INLINE { E::setBits(other, value, 27, 1); }
+       
+       uint8_t                 r_type() const                                  INLINE { return E::getBits(other, 28, 4); }
+       void                    set_r_type(uint8_t value)               INLINE { E::setBits(other, value, 28, 4); }
+               
+       void                    set_r_length()                                  INLINE { set_r_length((sizeof(typename P::uint_t)==8) ? 3 : 2); }
+
+       typedef typename P::E           E;
+private:
+       uint32_t                address;
+       uint32_t                other;
+};
+
+
+//
+// mach-o scattered relocation info
+// The bit fields are always in big-endian order (see mach-o/reloc.h)
+//
+template <typename P>
+class macho_scattered_relocation_info {
+public:
+       bool                    r_scattered() const                     INLINE { return BigEndian::getBitsRaw(E::get32(other), 0, 1); }
+       void                    set_r_scattered(bool x)         INLINE { uint32_t temp = E::get32(other); BigEndian::setBitsRaw(temp, x, 0, 1);  E::set32(other, temp); }
+
+       bool                    r_pcrel() const                         INLINE { return BigEndian::getBitsRaw(E::get32(other), 1, 1); }
+       void                    set_r_pcrel(bool x)                     INLINE { uint32_t temp = E::get32(other); BigEndian::setBitsRaw(temp, x, 1, 1);  E::set32(other, temp); }
+
+       uint8_t                 r_length() const                        INLINE { return BigEndian::getBitsRaw(E::get32(other), 2, 2); }
+       void                    set_r_length(uint8_t x)         INLINE { uint32_t temp = E::get32(other); BigEndian::setBitsRaw(temp, x, 2, 2);  E::set32(other, temp); }
+
+       uint8_t                 r_type() const                          INLINE { return BigEndian::getBitsRaw(E::get32(other), 4, 4); }
+       void                    set_r_type(uint8_t x)           INLINE { uint32_t temp = E::get32(other); BigEndian::setBitsRaw(temp, x, 4, 4);  E::set32(other, temp); }
+
+       uint32_t                r_address() const                       INLINE { return BigEndian::getBitsRaw(E::get32(other), 8, 24); }
+       void                    set_r_address(uint32_t x)       INLINE { uint32_t temp = E::get32(other); BigEndian::setBitsRaw(temp, x, 8, 24);  E::set32(other, temp); }
+
+       uint32_t                r_value() const                         INLINE { return E::get32(value); }
+       void                    set_r_value(uint32_t x)         INLINE { E::set32(value, x); }
+
+       uint32_t                r_other() const                         INLINE { return other; }
+       
+       typedef typename P::E           E;
+private:
+       uint32_t                other;
+       uint32_t                value;
+};
+
+
+
+
+
+
+#endif // __MACH_O_FILE_ABSTRACTION__
+
+
diff --git a/src/MachOReaderArchive.hpp b/src/MachOReaderArchive.hpp
new file mode 100644 (file)
index 0000000..d40ca70
--- /dev/null
@@ -0,0 +1,408 @@
+/* -*- 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 __OBJECT_FILE_ARCHIVE_MACH_O__
+#define __OBJECT_FILE_ARCHIVE_MACH_O__
+
+#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"
+
+
+namespace mach_o {
+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);
+       static Reader<A>*                                                               make(const uint8_t* fileContent, uint64_t fileLength, const char* path,
+                                                                                                               time_t modTime, const ObjectFile::ReaderOptions& options)
+                                                                                                               { return new Reader<A>(fileContent, fileLength, path, modTime, options); }
+       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; }
+
+private:
+       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;
+
+                                                                                                       Reader(const uint8_t fileContent[], uint64_t fileLength,
+                                                                                                                       const char* path, time_t modTime, const ObjectFile::ReaderOptions& options);
+       const struct ranlib*                                                    ranlibBinarySearch(const char* name);
+       const struct ranlib*                                                    ranlibLinearSearch(const char* name);
+       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;
+       const uint8_t*                                                                  fFileContent;
+       uint64_t                                                                                fFileLength;
+       const struct ranlib*                                                    fTableOfContents;
+       uint32_t                                                                                fTableOfContentCount;
+       const char*                                                                             fStringPool;
+       std::vector<class ObjectFile::Atom*>                    fAllAtoms;
+       std::set<const class Entry*>                                    fInstantiatedEntries;
+       std::set<const class Entry*>                                    fPossibleEntries;
+       NameToEntryMap                                                                  fHashTable;
+
+       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_size, 12);
+       temp[12] = '\0';
+       char* endptr;
+       return (time_t)strtol(temp, &endptr, 12);
+}
+
+
+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 <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 mach_o::relocatable::Reader<A>::validFile(p->getContent());
+       }       
+       // empty archive
+       return true;
+}
+
+template <typename A>
+Reader<A>::Reader(const uint8_t fileContent[], uint64_t fileLength, const char* path, time_t modTime, const ObjectFile::ReaderOptions& options)
+ : fPath(NULL), fModTime(modTime), fOptions(options), fFileContent(NULL), fTableOfContents(NULL), fTableOfContentCount(0),
+   fStringPool(NULL)
+{
+       fPath = strdup(path);
+       fFileContent = fileContent;
+       fFileLength = fileLength;
+
+       if ( strncmp((const char*)fileContent, "!<arch>\n", 8) != 0 )
+               throw "not an archive";
+
+       if ( !options.fFullyLoadArchives ) {
+               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 {
+               ObjectFile::Reader* obj = mach_o::relocatable::Reader<A>::make(member->getContent(), memberPath, fModTime, fOptions);
+               unsigned int objIndex = 0;
+               for (class std::set<const class Entry*>::iterator it=fPossibleEntries.begin(); it != fPossibleEntries.end(); it++, objIndex++) {
+                       if ( *it == member )
+                               break;
+               }
+               obj->setSortOrder((fSortOrder<<16) + objIndex);
+               //fprintf(stderr, "%s order = 0x%08X, index=%u\n", memberPath, obj->getSortOrder(), objIndex);
+               return obj;
+       }
+       catch (const char* msg) {
+               throwf("in %s, %s", memberPath, msg);
+       }
+}
+
+template <typename A>
+std::vector<class ObjectFile::Atom*>&  Reader<A>::getAtoms()
+{
+       if ( fOptions.fFullyLoadArchives ) {
+               // 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];
+               unsigned int objIndex = 0;
+               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;
+                       ObjectFile::Reader* r = this->makeObjectReaderForMember(p);
+                       r->setSortOrder((fSortOrder<<16) + objIndex++);
+                       std::vector<class ObjectFile::Atom*>&   atoms = r->getAtoms();
+                       fAllAtoms.insert(fAllAtoms.end(), atoms.begin(), atoms.end());
+               }
+               return fAllAtoms;
+       }
+       else {
+               // return nonthing for now, getJustInTimeAtomsFor() will return atoms as needed
+               return fgEmptyList;
+       }
+}
+
+
+template <typename A>
+ConstRanLibPtr Reader<A>::ranlibBinarySearch(const char* key)
+{
+       const struct ranlib* base = fTableOfContents;
+       for (uint32_t n = fTableOfContentCount; n > 0; n /= 2) {
+               const struct ranlib* pivot = &base[n/2];
+               const char* pivotStr = &fStringPool[E::get32(pivot->ran_un.ran_strx)];
+               int cmp = strcmp(key, pivotStr);
+               if ( cmp == 0 )
+                       return pivot;
+               if ( cmp > 0 ) {
+                       // key > pivot
+                       // move base to symbol after pivot
+                       base = &pivot[1];
+                       --n;
+               }
+               else {
+                       // key < pivot
+                       // keep same base
+               }
+       }
+       return NULL;
+}
+
+template <typename A>
+ConstRanLibPtr Reader<A>::ranlibLinearSearch(const char* key)
+{
+       for (uint32_t i = 0; i < fTableOfContentCount; ++i) {
+               const struct ranlib* entry = &fTableOfContents[i];
+               const char* entryName = &fStringPool[E::get32(entry->ran_un.ran_strx)];
+               if ( strcmp(key, entryName) == 0 )
+                       return entry;
+       }
+       return NULL;
+}
+
+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 ) {
+               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 ) {
+                               // only return these atoms once
+                               fInstantiatedEntries.insert(member);
+                               ObjectFile::Reader* r = makeObjectReaderForMember(member);
+                               //fprintf(stderr, "%s found in %s(%s)\n", name, this->getPath(), member->getName());
+                               return new std::vector<class ObjectFile::Atom*>(r->getAtoms());
+                       }
+               }
+               //fprintf(stderr, "%s NOT found in archive %s\n", name, fPath);
+               return NULL;
+       }
+}
+
+
+
+
+
+}; // namespace archive
+}; // namespace mach_o
+
+
+#endif // __OBJECT_FILE_ARCHIVE_MACH_O__
diff --git a/src/MachOReaderDylib.hpp b/src/MachOReaderDylib.hpp
new file mode 100644 (file)
index 0000000..e9ff931
--- /dev/null
@@ -0,0 +1,470 @@
+/* -*- 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 __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 "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 can 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                                                            isZeroFill() 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 bool                                                            requiresFollowOnAtom() const{ return false; }
+       virtual ObjectFile::Atom&                                       getFollowOnAtom() const         { return *((ObjectFile::Atom*)NULL); }
+       virtual std::vector<ObjectFile::LineInfo>*      getLineInfo() const                     { return NULL; }
+       virtual uint8_t                                                         getAlignment() const            { return 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)
+                                                                                               : fOwner(owner), fName(name), fWeakDefinition(weak) {}
+       virtual                                                                 ~ExportAtom() {}
+
+       ObjectFile::Reader&                                             fOwner;
+       const char*                                                             fName;
+       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;
+
+
+//
+// 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);
+       static Reader<A>*                                                               make(const uint8_t* fileContent, uint64_t fileLength, const char* path, const ObjectFile::ReaderOptions& options)
+                                                                                                               { return new Reader<A>(fileContent, fileLength, path, options); }
+       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 const char*                                                             getInstallPath()                        { return fDylibInstallPath; }
+       virtual uint32_t                                                                getTimestamp()                          { return fDylibTimeStamp; }
+       virtual uint32_t                                                                getCurrentVersion()                     { return fDylibtCurrentVersion; }
+       virtual uint32_t                                                                getCompatibilityVersion()       { return fDylibCompatibilityVersion; }
+       virtual std::vector<const char*>*                               getDependentLibraryPaths();
+       virtual bool                                                                    reExports(ObjectFile::Reader*);
+       virtual std::vector<const char*>*                               getAllowableClients();
+
+protected:
+               const char*                                                                     parentUmbrella()                        { return fParentUmbrella; }
+
+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; };
+       typedef __gnu_cxx::hash_map<const char*, AtomAndWeak, __gnu_cxx::hash<const char*>, CStringEquals> NameToAtomMap;
+       typedef typename NameToAtomMap::iterator                NameToAtomMapIterator;
+
+       struct PathAndFlag { const char* path; bool reExport; };
+
+                                                                                               Reader(const uint8_t* fileContent, uint64_t fileLength, const char* path, const ObjectFile::ReaderOptions& options);
+
+       const char*                                                                     fPath;
+       const char*                                                                     fParentUmbrella;
+       std::vector<const char*>                                        fAllowableClients;
+       const char*                                                                     fDylibInstallPath;
+       uint32_t                                                                        fDylibTimeStamp;
+       uint32_t                                                                        fDylibtCurrentVersion;
+       uint32_t                                                                        fDylibCompatibilityVersion;
+       std::vector<PathAndFlag>                                        fDependentLibraryPaths;
+       NameToAtomMap                                                           fAtoms;
+
+       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 ObjectFile::ReaderOptions& options)
+       : fParentUmbrella(NULL), fDylibInstallPath(NULL), fDylibTimeStamp(0), fDylibtCurrentVersion(0), fDylibCompatibilityVersion(0)
+{
+       // sanity check
+       if ( ! validFile(fileContent) )
+               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>));
+
+       // 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;
+       }
+
+       // pass 1 builds list of all dependent libraries
+       const macho_load_command<P>* cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               switch (cmd->cmd()) {
+                       case LC_LOAD_DYLIB:
+                       case LC_LOAD_WEAK_DYLIB:
+                               PathAndFlag entry;
+                               entry.path = strdup(((struct macho_dylib_command<P>*)cmd)->name());
+                               entry.reExport = false;
+                               fDependentLibraryPaths.push_back(entry);
+                               break;
+               }
+               cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
+       }
+
+       // pass 2 determines re-export info
+       const macho_dysymtab_command<P>* dynamicInfo = 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_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 ( !options.fFlatNamespace ) {
+                                       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 ( !options.fFlatNamespace ) {
+                                       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;
+               }
+
+               cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
+       }
+       // 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 ) 
+               throw "dylib missing LC_ID_DYLIB load command";
+       if ( symbolTable == NULL )
+               throw "dylib missing LC_SYMTAB load command";
+       if ( dynamicInfo == NULL )
+               throw "dylib missing LC_DYSYMTAB load command";
+       
+       // build hash table
+       if ( dynamicInfo->tocoff() == 0 ) {
+               if ( fgLogHashtable ) fprintf(stderr, "ld64: building hashtable of %u toc entries for %s\n", dynamicInfo->nextdefsym(), path);
+               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) {
+                       AtomAndWeak bucket;
+                       bucket.atom = NULL;
+                       bucket.weak = ((sym->n_desc() & N_WEAK_DEF) != 0);
+                       const char* name = strdup(&strings[sym->n_strx()]);
+                       if ( fgLogHashtable ) fprintf(stderr, "  adding %s to hash table for %s\n", name, this->getPath());
+                       fAtoms[name] = bucket;
+               }
+       }
+       else {
+               int32_t count = dynamicInfo->ntoc();
+               fAtoms.resize(count); // set initial bucket count
+               if ( fgLogHashtable ) fprintf(stderr, "ld64: building hashtable of %u entries for %s\n", count, path);
+               const struct dylib_table_of_contents* toc = (dylib_table_of_contents*)((char*)header + 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];
+                       AtomAndWeak bucket;
+                       bucket.atom = NULL;
+                       bucket.weak = ((sym->n_desc() & N_WEAK_DEF) != 0);
+                       const char* name = strdup(&strings[sym->n_strx()]);
+                       if ( fgLogHashtable ) fprintf(stderr, "  adding %s to hash table for %s\n", name, this->getPath());
+                       fAtoms[name] = bucket;
+               }
+       }
+
+       // unmap file
+       munmap((caddr_t)fileContent, fileLength);
+}
+
+template <typename A>
+std::vector<class ObjectFile::Atom*>& Reader<A>::getAtoms()
+{
+       // TO DO:       for flat-namespace libraries, when linking flat_namespace
+       //                      we need to create an atom which references all undefines
+       return fgEmptyAtomList;
+}
+
+
+template <typename A>
+std::vector<class ObjectFile::Atom*>* Reader<A>::getJustInTimeAtomsFor(const char* name)
+{
+       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);
+                       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());
+       }
+       return atoms;
+}
+
+
+
+template <typename A>
+std::vector<const char*>* Reader<A>::getDependentLibraryPaths()
+{
+       std::vector<const char*>* result = new std::vector<const char*>;
+       for (typename std::vector<PathAndFlag>::iterator it = fDependentLibraryPaths.begin(); it != fDependentLibraryPaths.end(); it++) {
+               result->push_back(it->path);
+       }
+       return result;
+}
+
+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 <typename A>
+bool Reader<A>::reExports(ObjectFile::Reader* child)
+{
+       // A dependent dylib is re-exported under two conditions:
+       //  1) parent contains LC_SUB_UMBRELLA or LC_SUB_LIBRARY with child name
+       for (typename std::vector<PathAndFlag>::iterator it = fDependentLibraryPaths.begin(); it != fDependentLibraryPaths.end(); it++) {
+               if ( it->reExport && (strcmp(it->path, child->getPath()) == 0) )
+                       return true;
+       }
+
+       //  2) child contains LC_SUB_FRAMEWORK with parent name
+       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) )
+                       return true;
+       }
+
+       return false;
+}
+
+template <>
+bool Reader<ppc>::validFile(const uint8_t* fileContent)
+{
+       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_DYLIB) && (header->filetype() != MH_DYLIB_STUB)  )
+               return false;
+       return true;
+}
+
+template <>
+bool Reader<ppc64>::validFile(const uint8_t* fileContent)
+{
+       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_DYLIB) && (header->filetype() != MH_DYLIB_STUB)  )
+               return false;
+       return true;
+}
+
+template <>
+bool Reader<x86>::validFile(const uint8_t* fileContent)
+{
+       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_DYLIB) && (header->filetype() != MH_DYLIB_STUB)  )
+               return false;
+       return true;
+}
+
+
+
+
+}; // namespace dylib
+}; // namespace mach_o
+
+
+#endif // __OBJECT_FILE_DYLIB_MACH_O__
diff --git a/src/MachOReaderRelocatable.hpp b/src/MachOReaderRelocatable.hpp
new file mode 100644 (file)
index 0000000..508be47
--- /dev/null
@@ -0,0 +1,2663 @@
+/* -*- 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 __OBJECT_FILE_MACH_O__
+#define __OBJECT_FILE_MACH_O__
+
+#include <stdint.h>
+#include <math.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <mach-o/ppc/reloc.h>
+#include <mach-o/stab.h>
+#ifndef S_ATTR_DEBUG
+ #define S_ATTR_DEBUG 0x02000000
+#endif
+
+#include <vector>
+#include <set>
+#include <algorithm>
+
+#include "MachOFileAbstraction.hpp"
+#include "Architectures.hpp"
+#include "ObjectFile.h"
+#include "dwarf2.h"
+#include "debugline.h"
+
+
+//
+//
+//     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, ...);
+
+namespace mach_o {
+namespace relocatable {
+
+
+
+// forward reference
+template <typename A> class Reader;
+template <typename A> class SymbolAtomSorter;
+
+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 bool                    isTargetUnbound() const                                                 { return ( fToTarget.atom == NULL ); }
+       virtual bool                    isFromTargetUnbound() const                                             { return ( fFromTarget.atom == NULL ); }
+       virtual uint8_t                 getKind() const                                                                 { return (uint8_t)fKind; }
+       virtual uint64_t                getFixUpOffset() const                                                  { return fFixUpOffsetInSrc; }
+       virtual const char*             getTargetName() const                                                   { return (fToTargetName != NULL) ? fToTargetName : fToTarget.atom->getName(); }
+       virtual ObjectFile::Atom& getTarget() const                                                             { return *fToTarget.atom; }
+       virtual uint64_t                getTargetOffset() const                                                 { return fToTarget.offset; }
+       virtual bool                    hasFromTarget() const                                                   { return ( (fFromTarget.atom != NULL) || (fFromTargetName != NULL) ); }
+       virtual ObjectFile::Atom& getFromTarget() const                                                 { return *fFromTarget.atom; }
+       virtual const char*             getFromTargetName() const                                               { return (fFromTargetName != NULL) ? fFromTargetName : fFromTarget.atom->getName(); }
+       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; }
+
+
+private:
+       pint_t                                  fFixUpOffsetInSrc;
+       AtomAndOffset                   fToTarget;
+       AtomAndOffset                   fFromTarget;
+       const char*                             fToTargetName;
+       const char*                             fFromTargetName;
+       Kinds                                   fKind;
+};
+
+
+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 where needed
+       if ( (kind != A::kNoFixUp) && (kind != A::kFollowOn) && (toTarget.atom->getScope() != ObjectFile::Atom::scopeTranslationUnit) ) {
+               fToTargetName = toTarget.atom->getName();
+               //fprintf(stderr, "Reference(): changing to by-name %p %s, target scope=%d\n", toTarget.atom, fToTargetName, toTarget.atom->getScope());
+               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) 
+               && (toTarget.atom->getScope() != ObjectFile::Atom::scopeTranslationUnit)
+               && (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>
+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(false),  fExecutable(false) 
+{
+       if ( strcmp(fSection->segname(), "__DATA") == 0 ) {
+               fWritable = true;
+       }
+       else if ( strcmp(fSection->segname(), "__OBJC") == 0 ) {
+               fWritable = true;
+       }
+       else if ( strcmp(fSection->segname(), "__TEXT") == 0 ) {
+               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 BaseAtom : public ObjectFile::Atom
+{
+public:
+                                                                                               BaseAtom() : fStabsStartIndex(0), fStabsCount(0) {}
+
+       virtual void                                                            setSize(uint64_t size)  = 0;
+       virtual void                                                            addReference(ObjectFile::Reference* ref) = 0;
+       virtual void                                                            addLineInfo(const ObjectFile::LineInfo& info) = 0;
+       virtual void                                                            alignAtLeast(uint8_t align)     = 0;
+
+       uint32_t                                                                        fStabsStartIndex;
+       uint32_t                                                                        fStabsCount;
+};
+
+
+//
+// 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 SymbolTableInclusion                            getSymbolTableInclusion() const { return ((fSymbol->n_desc() & REFERENCED_DYNAMICALLY) != 0)
+                                                                                                                                                                               ? ObjectFile::Atom::kSymbolTableInAndNeverStrip : ObjectFile::Atom::kSymbolTableIn; }
+       virtual bool                                                            isZeroFill() const                              { return ((fSection->flags() & SECTION_TYPE) == S_ZEROFILL); }
+       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 bool                                                            requiresFollowOnAtom() const;
+       virtual ObjectFile::Atom&                                       getFollowOnAtom() const;
+       virtual std::vector<ObjectFile::LineInfo>*      getLineInfo() const                             { return (std::vector<ObjectFile::LineInfo>*)&fLineInfo; }
+       virtual uint8_t                                                         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.insert(fReferences.begin(), (Reference<A>*)ref); }
+       virtual void                                                            addLineInfo(const  ObjectFile::LineInfo& info)  { fLineInfo.push_back(info); }
+       virtual void                                                            alignAtLeast(uint8_t align)             { fAlignment = std::max(align, fAlignment); }
+
+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>;
+       friend class SymbolAtomSorter<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;
+       uint8_t                                                                         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), fAlignment(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();
+               if ( (fSymbol->n_desc() & N_NO_DEAD_STRIP) != 0 )
+                       this->setDontDeadStrip();
+       }
+       else {
+               printf("unknown symbol type: %d\n", 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_CSTRING_LITERALS:
+                       setSize(strlen((char*)(fOwner.fHeader) + section->offset() + fAddress - section->addr()) + 1);
+               case S_REGULAR:
+               case S_ZEROFILL:
+               case S_COALESCED:
+                       // size calculate later after next atom is found
+                       break;
+       }
+}
+
+
+template <typename A>
+void SymbolAtom<A>::setSize(uint64_t size)
+{
+       fSize = size;
+       
+       // Try to compute the alignment base on the address aligned at in object file and the size
+       uint8_t sizeAlign = __builtin_ctz(fSize);
+       uint8_t sizeAndSectAlign = std::min((uint8_t)fSection->align(), sizeAlign);
+       // If address is zero, can't figure out better alignment than section alignment and size
+       if ( fAddress == 0 )
+               fAlignment = sizeAndSectAlign;
+       else
+               fAlignment = std::min((uint8_t)__builtin_ctz(fAddress), sizeAndSectAlign);
+}
+
+
+template <typename A>
+const char*    SymbolAtom<A>::getSectionName() 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>
+bool SymbolAtom<A>::requiresFollowOnAtom() const
+{
+       // requires follow-on if built with old compiler and not the last atom
+       if ( (fOwner.fHeader->flags() & MH_SUBSECTIONS_VIA_SYMBOLS) == 0) {
+               for (ReferenceVectorConstIterator it=fReferences.begin(); it != fReferences.end(); it++) {
+                       Reference<A>* ref = *it;
+                       if ( ref->getKind() == A::kFollowOn )
+                               return true;
+               }
+       }
+       return false;
+}
+
+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>
+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);
+       }
+}
+
+
+template <typename A>
+class SymbolAtomSorter
+{
+public:
+       SymbolAtomSorter(std::map<uint32_t, BaseAtom*>& map) : fMap(map) {}
+       
+       typedef typename A::P::uint_t pint_t;
+       
+       bool operator()(ObjectFile::Atom* left, ObjectFile::Atom* right)
+       {
+               pint_t leftAddr  = ((SymbolAtom<A>*)left)->fAddress;
+               pint_t rightAddr = ((SymbolAtom<A>*)right)->fAddress;
+               if ( leftAddr == rightAddr ) {
+                       // two atoms with same address, must have been a function with multiple labels
+                       // make sure we sort these so the one with real content (in map) is last
+                       std::map<uint32_t, BaseAtom*>::iterator pos = fMap.find(leftAddr);
+                       if ( pos != fMap.end() ) {
+                               return ( pos->second == right );
+                       }
+                       return false;
+               }
+               else {
+                       return ( leftAddr < rightAddr );
+               }
+       }
+private:
+       std::map<uint32_t, BaseAtom*>&  fMap;
+};
+
+
+//
+// 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 true; }
+       virtual SymbolTableInclusion                            getSymbolTableInclusion() const { return ((fSymbol->n_desc() & REFERENCED_DYNAMICALLY) != 0)
+                                                                                                                                                                               ? ObjectFile::Atom::kSymbolTableInAndNeverStrip : ObjectFile::Atom::kSymbolTableIn; }
+       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                  { return "__common"; }
+       virtual ObjectFile::Segment&                            getSegment() const                              { return DataSegment::fgSingleton; }
+       virtual bool                                                            requiresFollowOnAtom() const    { return false; }
+       virtual ObjectFile::Atom&                                       getFollowOnAtom() const                 { return *(ObjectFile::Atom*)NULL; }
+       virtual std::vector<ObjectFile::LineInfo>*      getLineInfo() const                             { return NULL; }
+       virtual uint8_t                                                         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 "can't add references"; }
+       virtual void                                                            addLineInfo(const  ObjectFile::LineInfo& info)  { throw "can't add line info to tentative definition"; }
+       virtual void                                                            alignAtLeast(uint8_t align)             { }
+
+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 {
+               printf("unknown symbol type: %d\n", type);
+       }
+       //fprintf(stderr, "TentativeAtom(%p) %s\n", this, this->getDisplayName());
+}
+
+
+template <typename A>
+uint8_t        TentativeAtom<A>::getAlignment() const
+{
+       // common symbols align to their size
+       // that is, a 4-byte common aligns to 4-bytes
+       // to be safe, odd size commons align to the next power-of-2 size
+       uint8_t alignment = (uint8_t)ceil(log2(this->getSize()));
+       // limit alignment of extremely large commons to 2^15 bytes (8-page)
+       if ( alignment < 15 )
+               return alignment;
+       else
+               return 15;
+}
+
+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;
+       virtual ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const  { return ObjectFile::Atom::kSymbolTableNotIn; }
+       virtual bool                                                            isZeroFill() const;
+       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 bool                                                            requiresFollowOnAtom() const;
+       virtual ObjectFile::Atom&                                       getFollowOnAtom() const;
+       virtual std::vector<ObjectFile::LineInfo>*      getLineInfo() const                             { return NULL; }
+       virtual uint8_t                                                         getAlignment() const;
+       virtual void                                                            copyRawContent(uint8_t buffer[]) const;
+       virtual void                                                            setScope(ObjectFile::Atom::Scope newScope)              { }
+       virtual void                                                            setSize(uint64_t size)                  { fSize = size; }
+       virtual void                                                            addReference(ObjectFile::Reference* ref) { fReferences.insert(fReferences.begin(), (Reference<A>*)ref); }
+       virtual void                                                            addLineInfo(const  ObjectFile::LineInfo& info)  { fprintf(stderr, "can't add line info to anonymous symbol %s\n", this->getDisplayName()); }
+       virtual void                                                            alignAtLeast(uint8_t align)             { }
+       BaseAtom*                                                                       redirectTo()                                    { return fRedirect; }
+       bool                                                                            isWeakImportStub()                              { return fWeakImportStub; }
+
+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>*, uint32_t addr, uint32_t size);
+       virtual                                                                 ~AnonymousAtom() {}
+
+       Reader<A>&                                                                      fOwner;
+       const char*                                                                     fSynthesizedName;
+       const macho_section<P>*                                         fSection;
+       uint32_t                                                                        fAddress;
+       uint32_t                                                                        fSize;
+       Segment<A>*                                                                     fSegment;
+       ReferenceVector                                                         fReferences;
+       BaseAtom*                                                                       fRedirect;
+       bool                                                                            fWeakImportStub;
+       bool                                                                            fReallyNonLazyPointer;  // HACK until compiler stops emitting anonymous non-lazy pointers
+};
+
+template <typename A>
+AnonymousAtom<A>::AnonymousAtom(Reader<A>& owner, const macho_section<P>* section, uint32_t addr, uint32_t size)
+ : fOwner(owner), fSynthesizedName(NULL), fSection(section), fAddress(addr), fSize(size), fSegment(NULL), 
+       fWeakImportStub(false), fReallyNonLazyPointer(false)
+{
+       fSegment = new Segment<A>(fSection);
+       fRedirect = this;
+       uint8_t type = fSection->flags() & SECTION_TYPE;
+       switch ( type ) {
+               case S_ZEROFILL:
+                       {
+                               asprintf((char**)&fSynthesizedName, "zero-fill-at-0x%08X", addr);
+                       }
+                       break;
+               case S_REGULAR:
+                       // handle .o files created by old ld64 -r that are missing cstring section type
+                       if ( strcmp(fSection->sectname(), "__cstring") != 0 )
+                               break;
+                       // else fall into cstring case
+               case S_CSTRING_LITERALS:
+                       {
+                               const char* str = (char*)(owner.fHeader) + section->offset() + addr - section->addr();
+                               asprintf((char**)&fSynthesizedName, "cstring=%s", str);
+                       }
+                       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);
+                       }
+                       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);
+                       }
+                       break;
+               case S_LITERAL_POINTERS:
+                       {
+                               // FIX FIX, we need the name to include the name of the target so that we can coalesce them
+                               asprintf((char**)&fSynthesizedName, "literal-pointer@%d", addr - (uint32_t)fSection->addr());
+                       }
+                       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_desc() & N_WEAK_DEF) == 0) ) {
+                                       BaseAtom* staticAtom = fOwner.findAtomByName(fSynthesizedName);
+                                       if ( staticAtom != NULL )
+                                               fRedirect = staticAtom;
+                               }
+                       }
+                       break;
+               case S_LAZY_SYMBOL_POINTERS:
+               case S_NON_LAZY_SYMBOL_POINTERS:
+                       {
+                               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
+                                       // All atoms not created yet, so we need to scan symbol table
+                                       uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
+                                       pint_t nonLazyPtrValue = P::getP(*((pint_t*)((char*)(fOwner.fHeader)+fileOffset)));
+                                       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_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);
+                                                       return;
+                                               }
+                                       }
+                                       throwf("malformed .o file: non-lazy-pointer with value 0x%08X missing symbol", nonLazyPtrValue);
+                               }
+                               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");
+                               else
+                                       strcat(str, "$non_lazy_ptr");
+                               fSynthesizedName = str;
+
+                               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%08X", type, addr);
+       }
+       //fprintf(stderr, "AnonymousAtom(%p) %s \n", this, this->getDisplayName());
+}
+
+
+template <typename A>
+const char* AnonymousAtom<A>::getDisplayName() const
+{
+       if ( fSynthesizedName != NULL )
+               return fSynthesizedName;
+
+       static char temp[512];
+       if ( (fSection->flags() & SECTION_TYPE) == S_CSTRING_LITERALS ) {
+               uint32_t fileOffset = fSection->offset() - fSection->addr() + fAddress;
+               sprintf(temp, "atom string literal: \"%s\"", (char*)(fOwner.fHeader)+fileOffset);
+       }
+       else {
+               sprintf(temp, "%s@%d", fSection->sectname(), fAddress - (uint32_t)fSection->addr() );
+       }
+       return temp;
+}
+
+template <typename A>
+ObjectFile::Atom::Scope AnonymousAtom<A>::getScope() const
+{
+       if ( fReallyNonLazyPointer )
+               return ObjectFile::Atom::scopeLinkageUnit;
+       // in order for literals to be coalesced they must be scoped to linkage unit
+       switch ( fSection->flags() & SECTION_TYPE ) {
+               case S_CSTRING_LITERALS:
+               case S_4BYTE_LITERALS:
+               case S_8BYTE_LITERALS:
+               case S_SYMBOL_STUBS:
+               case S_NON_LAZY_SYMBOL_POINTERS:
+                       return ObjectFile::Atom::scopeLinkageUnit;
+               default:
+                       return ObjectFile::Atom::scopeTranslationUnit;
+       }
+}
+
+template <typename A>
+ObjectFile::Atom::DefinitionKind AnonymousAtom<A>::getDefinitionKind() const
+{
+       if ( fReallyNonLazyPointer )
+               return  ObjectFile::Atom::kWeakDefinition;
+       // in order for literals to be coalesced they must be weak
+       switch ( fSection->flags() & SECTION_TYPE ) {
+               case S_CSTRING_LITERALS:
+               case S_4BYTE_LITERALS:
+               case S_8BYTE_LITERALS:
+               case S_NON_LAZY_SYMBOL_POINTERS:
+                       return ObjectFile::Atom::kWeakDefinition;
+               default:
+                       return ObjectFile::Atom::kRegularDefinition;
+       }
+}
+
+template <typename A>
+bool AnonymousAtom<A>::isZeroFill() const
+{
+       return ( (fSection->flags() & SECTION_TYPE) == S_ZEROFILL );
+}
+
+
+template <typename A>
+const char*    AnonymousAtom<A>::getSectionName() const
+{
+       if ( fReallyNonLazyPointer )
+               return "__nl_symbol_ptr";
+       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>
+uint8_t AnonymousAtom<A>::getAlignment() const
+{
+       if ( fReallyNonLazyPointer )
+               return (uint8_t)log2(sizeof(pint_t));
+       switch ( fSection->flags() & SECTION_TYPE ) {
+               case S_4BYTE_LITERALS:
+                       return 2;
+               case S_8BYTE_LITERALS:
+                       return 3;
+               case S_NON_LAZY_SYMBOL_POINTERS:
+                       return (uint8_t)log2(sizeof(pint_t));
+               default:
+                       return fSection->align();
+       }
+}
+
+template <typename A>
+bool AnonymousAtom<A>::requiresFollowOnAtom() const
+{
+       // requires follow-on if built with old compiler and not the last atom
+       if ( (fOwner.fHeader->flags() & MH_SUBSECTIONS_VIA_SYMBOLS) == 0) {
+               for (ReferenceVectorConstIterator it=fReferences.begin(); it != fReferences.end(); it++) {
+                       Reference<A>* ref = *it;
+                       if ( ref->getKind() == A::kFollowOn )
+                               return true;
+               }
+       }
+       return false;
+}
+
+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);
+       }
+}
+
+
+
+
+template <typename A>
+class Reader : public ObjectFile::Reader
+{
+public:
+       static bool                                                                             validFile(const uint8_t* fileContent);
+       static Reader<A>*                                                               make(const uint8_t* fileContent, const char* path, time_t modTime,
+                                                                                                                       const ObjectFile::ReaderOptions& options)
+                                                                                                               { return new Reader<A>(fileContent, path, modTime, options); }
+       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; }
+
+        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;
+       friend class AnonymousAtom<A>;
+       friend class TentativeAtom<A>;
+       friend class SymbolAtom<A>;
+                                                                                               Reader(const uint8_t* fileContent, const char* path, time_t modTime, const ObjectFile::ReaderOptions& options);
+       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);
+       Kinds                                                                           pointerDiffKindForLength_powerpc(uint8_t r_length);
+       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(uint32_t addr);
+       AtomAndOffset                                                           findAtomAndOffset(uint32_t baseAddr, uint32_t realAddr);
+       Reference<A>*                                                           makeReference(Kinds kind, uint32_t atAddr, uint32_t toAddr);
+       Reference<A>*                                                           makeReference(Kinds kind, uint32_t atAddr, uint32_t fromAddr, uint32_t toAddr);
+       Reference<A>*                                                           makeReferenceWithToBase(Kinds kind, uint32_t atAddr, uint32_t toAddr, uint32_t toBaseAddr);
+       Reference<A>*                                                           makeReferenceWithToBase(Kinds kind, uint32_t atAddr, uint32_t fromAddr, uint32_t toAddr, uint32_t toBaseAddr);
+       Reference<A>*                                                           makeByNameReference(Kinds kind, uint32_t atAddr, const char* toName, uint32_t toOffset);
+       Reference<A>*                                                           makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section<P>* ehSect);
+       void                                                                            validSectionType(uint8_t type);
+
+       BaseAtom*                                                                       findAtomByName(const char*);
+
+       const char*                                                                     fPath;
+       time_t                                                                          fModTime;
+       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<ObjectFile::Atom*>                          fAtoms;
+       std::map<uint32_t, BaseAtom*>                           fAddrToAtom;
+       std::vector<class AnonymousAtom<A>*>            fLocalNonLazys;
+       ObjectFile::Reader::DebugInfoKind                       fDebugInfo;
+       const macho_section<P>*                                         fDwarfDebugInfoSect;
+       const macho_section<P>*                                         fDwarfDebugAbbrevSect;
+       const macho_section<P>*                                         fDwarfDebugLineSect;
+       const char*                                                                     fDwarfTranslationUnitDir;
+       const char*                                                                     fDwarfTranslationUnitFile;
+       std::map<uint32_t,const char*>                          fDwarfIndexToFile;
+       std::vector<Stab>                                                       fStabs;
+};
+
+
+template <typename A>
+Reader<A>::Reader(const uint8_t* fileContent, const char* path, time_t modTime, const ObjectFile::ReaderOptions& options)
+       : fPath(strdup(path)), fModTime(modTime), fOptions(options), fHeader((const macho_header<P>*)fileContent),
+        fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fSegment(NULL), fIndirectTable(NULL),
+        fDebugInfo(kDebugInfoNone), fDwarfDebugInfoSect(NULL), fDwarfDebugAbbrevSect(NULL),
+         fDwarfTranslationUnitDir(NULL), fDwarfTranslationUnitFile(NULL)
+{
+       // sanity check
+       if ( ! validFile(fileContent) )
+               throw "not a valid mach-o object file";
+
+       // cache intersting pointers
+       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>* 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;
+                                       fSymbolCount = symtab->nsyms();
+                                       fSymbols = (const macho_nlist<P>*)((char*)header + symtab->symoff());
+                                       fStrings = (char*)header + symtab->stroff();
+                               }
+                               break;
+                       case LC_DYSYMTAB:
+                               {
+                                       const macho_dysymtab_command<P>* dsymtab = (struct macho_dysymtab_command<P>*)cmd;
+                                       fIndirectTable = (uint32_t*)((char*)fHeader + dsymtab->indirectsymoff());
+                               }
+                               break;
+                   case LC_UUID:
+                               if (getDebugInfoKind() != kDebugInfoDwarf)
+                                       fDebugInfo = kDebugInfoStabsUUID;
+                               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());
+       }
+       const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)fSegment + sizeof(macho_segment_command<P>));
+       const macho_section<P>* const sectionsEnd = &sectionsStart[fSegment->nsects()];
+
+       // inital guess for number of atoms
+       fAtoms.reserve(fSymbolCount);
+
+       // add all atoms that have entries in symbol table
+       const macho_section<P>* sections = (macho_section<P>*)((char*)fSegment + sizeof(macho_segment_command<P>));
+       for (uint32_t i=0; i < fSymbolCount; ++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 ) {
+                               const macho_section<P>* section = &sections[sym.n_sect()-1];
+                               bool suppress = false;
+                               // ignore atoms in debugger sections
+                               if ( (section->flags() & S_ATTR_DEBUG) == 0 ) {
+                                       // 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_CSTRING_LITERALS:
+                                                       {
+                                                               BaseAtom* newAtom = new SymbolAtom<A>(*this, &sym, section);
+                                                               std::map<uint32_t, BaseAtom*>::iterator pos = fAddrToAtom.find(sym.n_value());
+                                                               if ( pos != fAddrToAtom.end() ) {
+                                                                       // another label to an existing address
+                                                                       // make this one be the real one and followed by the previous 
+                                                                       BaseAtom* existingAtom = pos->second;
+                                                                       //fprintf(stderr, "new atom %s has same address as existing atom %s\n", newAtom->getDisplayName(), existingAtom->getDisplayName());
+                                                                       new Reference<A>(A::kFollowOn, AtomAndOffset(newAtom), AtomAndOffset(existingAtom));
+                                                                       newAtom->setSize(0);
+                                                               }
+                                                               else {
+                                                                       fAddrToAtom[sym.n_value()] = 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:
+                                                       fprintf(stderr, "ld64 warning: symbol %s found in unsupported section in %s\n",
+                                                               &fStrings[sym.n_strx()], this->getPath());
+                                       }
+                               }
+                       }
+                       else if ( (type == N_UNDF) && (sym.n_value() != 0) ) {
+                               fAtoms.push_back(new TentativeAtom<A>(*this, &sym));
+                       }
+               }
+       }
+
+       // sort SymbolAtoms by address
+       std::sort(fAtoms.begin(), fAtoms.end(), SymbolAtomSorter<A>(fAddrToAtom));
+
+       // add all fixed size anonymous atoms from special sections
+       for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+               uint32_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;
+               }
+               if ( atomSize != 0 ) {
+                       for(uint32_t sectOffset=0; sectOffset < sect->size(); sectOffset += atomSize) {
+                               uint32_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=sectionsStart; sect < sectionsEnd; ++sect) {
+               if ( ((sect->flags() & SECTION_TYPE) == S_CSTRING_LITERALS) || strcmp(sect->sectname(), "__cstring") == 0 ) {
+                       uint32_t stringLen;
+                       uint32_t stringAddr;
+                       BaseAtom* firstEmptyString = NULL;
+                       for(uint32_t sectOffset=0; sectOffset < sect->size(); sectOffset += stringLen) {
+                               stringAddr = sect->addr() + sectOffset;
+                               stringLen  = strlen((char*)(fHeader) + sect->offset() + sectOffset) + 1;
+                               // add if not already an atom at that address
+                               if ( fAddrToAtom.find(stringAddr) == fAddrToAtom.end() ) {
+                                       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
+                                               // map them all to the first empty string
+                                               if ( firstEmptyString == NULL ) {
+                                                       firstEmptyString = newAtom;
+                                                       fAtoms.push_back(firstEmptyString);
+                                               }
+                                               fAddrToAtom[stringAddr] = firstEmptyString;
+                                       }
+                                       else {
+                                               fAtoms.push_back(newAtom);
+                                               fAddrToAtom[stringAddr] = newAtom;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       // create atoms to cover any non-debug ranges not handled above
+       for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+               pint_t sectionStartAddr = sect->addr();
+               pint_t sectionEndAddr   = sect->addr() + sect->size();
+               const bool setFollowOnAtom = ((fHeader->flags() & MH_SUBSECTIONS_VIA_SYMBOLS) == 0);
+               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->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:
+                                               // detect if compiler has generated anonymous non-lazy pointers at end of __data section
+                                               // HACK BEGIN - until compiler stops generated anonymous non-lazy pointers
+                                               if ( (sect->size() >= sizeof(pint_t)) 
+                                                       && ((sect->size() % sizeof(pint_t)) == 0) 
+                                                       && (sect->align() >= log2(sizeof(pint_t)))
+                                                       && (strcmp(sect->sectname(), "__data") == 0)
+                                                       && (strcmp(sect->segname(), "__DATA") == 0) ) {
+                                                               // find every pointer sized external reloc from end of section and split off into own atom
+                                                               uint32_t possiblePointerAddress = sect->size() - sizeof(pint_t);
+                                                               const uint8_t* sectionContent = ((uint8_t*)(fHeader))+sect->offset();
+                                                               const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fHeader) + sect->reloff());
+                                                               const macho_relocation_info<P>* relocsEnd = &relocs[sect->nreloc()];
+                                                               for (const macho_relocation_info<P>* r = relocs; r < relocsEnd; ++r) {
+                                                                       if ( ((r->r_address() & R_SCATTERED) == 0) 
+                                                                               && r->r_extern() 
+                                                                               && (r->r_address() == possiblePointerAddress)
+                                                                               && (fAddrToAtom.find(possiblePointerAddress+sect->addr()) == fAddrToAtom.end())
+                                                                               && (P::getP(*((pint_t*)(sectionContent+possiblePointerAddress))) == 0) ) {
+                                                                                       // create an anonymous atom to cover this non-lazy pointer
+                                                                                       AnonymousAtom<A>* newAtom = new AnonymousAtom<A>(*this, sect, sect->addr()+possiblePointerAddress, sizeof(pint_t));
+                                                                                       const macho_nlist<P>* targetSymbol = &fSymbols[r->r_symbolnum()];
+                                                                                       char* name;
+                                                                                       asprintf(&name, "%s$non_lazy_ptr", &fStrings[targetSymbol->n_strx()]);
+                                                                                       newAtom->fSynthesizedName = name;
+                                                                                       newAtom->fReallyNonLazyPointer = true;
+                                                                                       fAtoms.push_back(newAtom);
+                                                                                       fAddrToAtom[sect->addr()+possiblePointerAddress] = newAtom;
+                                                                                       possiblePointerAddress -= sizeof(pint_t);
+                                                                                       sectionEndAddr -= sizeof(pint_t);
+                                                                       }
+                                                                       else {
+                                                                               break;
+                                                                       }
+                                                               }
+                                               }
+                                               // HACK END - until compiler stops generated anonymous non-lazy pointers
+                                               uint32_t previousAtomAddr = 0;
+                                               BaseAtom* previousAtom = NULL;
+                                               if ( fAddrToAtom.find(sectionStartAddr) == fAddrToAtom.end() ) {
+                                                       // if there is not an atom already at the start of this section, add an anonymous one
+                                                       BaseAtom* newAtom = new AnonymousAtom<A>(*this, sect, sect->addr(), 0);
+                                                       fAtoms.push_back(newAtom);
+                                                       fAddrToAtom[sect->addr()] = newAtom;
+                                                       previousAtomAddr = sectionStartAddr;
+                                                       previousAtom = newAtom;
+                                               }
+                                               // calculate size of all atoms in this section and add follow-on references
+                                               for (std::map<uint32_t, BaseAtom*>::iterator it=fAddrToAtom.begin(); it != fAddrToAtom.end(); it++) {
+                                                       // note: this algorithm depends on the map iterator returning entries in address order
+                                                       if ( (it->first >= sectionStartAddr) && (it->first < sectionEndAddr) ) {
+                                                               //fprintf(stderr, "  atom %s in section\n", it->second->getDisplayName());
+                                                               if ( previousAtom != NULL ) {
+                                                                       previousAtom->setSize(it->first - previousAtomAddr);
+                                                                       // FIX FIX: this setting of followOn atoms does not work when there are multiple
+                                                                       // labels for the same atom
+                                                                       if ( setFollowOnAtom && (it->second != previousAtom) )
+                                                                               makeReference(A::kFollowOn, previousAtomAddr, it->first);
+                                                               }
+                                                               previousAtomAddr = it->first;
+                                                               previousAtom = it->second;
+                                                       }
+                                               }
+                                               if ( previousAtom != NULL ) {
+                                                       // set last atom in section
+                                                       previousAtom->setSize(sectionEndAddr - previousAtomAddr);
+                                               }
+                                               break;
+                               }
+                       }
+               }
+       }
+
+       // add relocation based references
+       for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+               // ignore dwarf sections.  If ld every 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:
+                                       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\n", sect->segname(), sect->sectname(), r, msg);
+                                               }
+                                       }
+                       }
+               }
+       }
+
+       // 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 implicit direct reference from each C++ function to its eh info
+       for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+               if ( ((sect->flags() & SECTION_TYPE) == S_COALESCED) && (strcmp(sect->sectname(), "__eh_frame") == 0) ) {
+                       for (std::map<uint32_t, BaseAtom*>::iterator it=fAddrToAtom.begin(); it != fAddrToAtom.end(); it++) {
+                               // note: this algorithm depens on the map iterator returning entries in address order
+                               if ( (it->first >= sect->addr()) && (it->first < sect->addr()+sect->size()) ) {
+                                       uint32_t ehAtomAddress = it->first;
+                                       BaseAtom* ehAtom = it->second;
+                                       const char* ehName = ehAtom->getName();
+                                       if ( (ehName != NULL) && (strcmp(&ehName[strlen(ehName)-3], ".eh") == 0) ) 
+                                               makeReferenceToEH(ehName, ehAtomAddress, sect);
+                               }
+                       }
+               }
+       }
+
+
+       //for (std::map<uint32_t, BaseAtom*>::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) ) {
+               if ( !read_comp_unit(&fDwarfTranslationUnitFile, &fDwarfTranslationUnitDir, &stmtList) ) {
+                       // if can't parse dwarf, warn and give up
+                       fDwarfTranslationUnitFile = NULL;
+                       fDwarfTranslationUnitDir = NULL;
+                       fprintf(stderr, "ld64: warning can't parse dwarf compilation unit info in %s\n", 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) ) {
+                       // 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;
+                                       while ( line_next (lines, &result, line_stop_line) ) {
+                                               // for performance, see if in next pc is in current atom
+                                               if ( (curAtom != NULL) && (result.pc <= curAtomAddress+curAtomSize) && (curAtomAddress <= result.pc) ) {
+                                                       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
+                                                       curAtomOffset   = ao.offset;
+                                                       curAtomAddress  = result.pc;
+                                                       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\n", result.pc, result.line, filename);
+                                               ((BaseAtom*)curAtom)->addLineInfo(info);
+                                       }
+                                       line_free(lines);
+                               }
+                               else {
+                                       fprintf(stderr, "ld64: warning could not parse dwarf line number info in %s\n", 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];
+                       uint8_t type = sym->n_type();
+                       const char* symString = (sym->n_strx() != 0) ? &fStrings[sym->n_strx()] : NULL;
+                       if ( (type & N_STAB) != 0 ) {
+                               fDebugInfo = 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\n",
+                                                                               (uint64_t)sym->n_value(), path);
+                                                               }
+                                                               break;
+                                                       case N_SO:
+                                                       case N_OSO:
+                                                       case N_OPT:
+                                                       case N_LSYM:
+                                                               // 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;
+                                                                       }
+                                                               }
+                                                               if ( stab.atom == NULL ) {
+                                                                       fprintf(stderr, "can't find atom for N_GSYM stabs %s in %s\n", symString, path);
+                                                               }
+                                                               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 {
+                                                                       fprintf(stderr, "can't find atom for stabs FUN at %08llX in %s\n",
+                                                                               (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:
+                                                               fprintf(stderr, "unknown stabs type 0x%X in %s\n", 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 {
+                                                                       fprintf(stderr, "can't find atom for stabs 0x%X at %08llX in %s\n",
+                                                                               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 {
+                                                                               fprintf(stderr, "can't find atom for stabs FUN at %08llX in %s\n",
+                                                                                       (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
+                               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
+}
+
+
+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 true;
+       }
+       return false;
+}
+
+template <typename A>
+BaseAtom* Reader<A>::findAtomByName(const char* name)
+{
+       // first search the more important atoms
+       for (std::map<uint32_t, BaseAtom*>::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<ObjectFile::Atom*>::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, uint32_t atAddr, uint32_t toAddr)
+{
+       return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(toAddr));
+}
+
+template <typename A>
+Reference<A>* Reader<A>::makeReference(Kinds kind, uint32_t atAddr, uint32_t fromAddr, uint32_t toAddr)
+{
+       return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(fromAddr), findAtomAndOffset(toAddr));
+}
+
+template <typename A>
+Reference<A>* Reader<A>::makeReferenceWithToBase(Kinds kind, uint32_t atAddr, uint32_t toAddr, uint32_t toBaseAddr)
+{
+       return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(toBaseAddr, toAddr));
+}
+
+template <typename A>
+Reference<A>* Reader<A>::makeReferenceWithToBase(Kinds kind, uint32_t atAddr, uint32_t fromAddr, uint32_t toAddr, uint32_t toBaseAddr)
+{
+       return new Reference<A>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(fromAddr), findAtomAndOffset(toBaseAddr, toAddr));
+}
+
+template <typename A>
+Reference<A>* Reader<A>::makeByNameReference(Kinds kind, uint32_t atAddr, const char* toName, uint32_t toOffset)
+{
+       return new Reference<A>(kind, findAtomAndOffset(atAddr), toName, toOffset);
+}
+
+template <typename A>
+Reference<A>* Reader<A>::makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section<P>* ehSect)
+{
+       // add a direct 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
+       uint32_t funcAddr = ehAtomAddress + deltaMinus8 + 8;
+       return makeReference(A::kNoFixUp, funcAddr, ehAtomAddress)      ;
+}
+
+
+
+template <typename A>
+AtomAndOffset Reader<A>::findAtomAndOffset(uint32_t addr)
+{
+       // STL has no built-in for "find largest key that is same or less than"
+       std::map<uint32_t, BaseAtom*>::iterator it = fAddrToAtom.upper_bound(addr);
+       --it; // upper_bound gets us next key, so we back up one
+       AtomAndOffset result;
+       result.atom = it->second;
+       result.offset = addr - it->first;
+       //fprintf(stderr, "findAtomAndOffset(0x%0X) ==> %s (0x%0X -> 0x%0llX)\n",
+       //                      addr, result.atom->getDisplayName(), 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(uint32_t baseAddr, uint32_t realAddr)
+{
+       std::map<uint32_t, BaseAtom*>::iterator it = fAddrToAtom.find(baseAddr);
+       if ( it != fAddrToAtom.end() ) {
+               AtomAndOffset result;
+               result.atom = it->second;
+               result.offset = realAddr - it->first;
+               //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
+       // we should never get here...
+       // one case we do get here is because sometimes the compiler generates non-lazy pointers in the __data section
+       return findAtomAndOffset(realAddr);
+}
+
+
+/* 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 = dwarf64 ? 8 : 4;
+      break;
+
+    default:
+      return false;
+    }
+  if (end - *offset < sz)
+    return false;
+  *offset += sz;
+  return true;
+}
+
+// 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 && form == DW_FORM_string)
+                       *name = (const char *) di;
+               else if (attr == DW_AT_comp_dir && form == DW_FORM_string)
+                       *comp_dir = (const char *) di;
+               /* Really we should support DW_FORM_strp here, too, but
+               there's usually no reason for the producer to use that form
+                for the DW_AT_name and DW_AT_comp_dir attributes.  */
+               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)
+{
+       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)
+{
+       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)
+{
+       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 <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 ( 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;
+                                               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 ) {
+                                               printf("PPC_RELOC_LO16 missing following pair\n");
+                                               break;
+                                       }
+                                       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);
+                                               makeReference(A::kAbsLow16, srcAddr, dstAddr);
+                                       }
+                               }
+                               break;
+                       case PPC_RELOC_LO14:
+                               {
+                                       if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
+                                               printf("PPC_RELOC_LO14 missing following pair\n");
+                                               break;
+                                       }
+                                       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);
+                                               Reference<A>* ref = makeReference(A::kAbsLow14, srcAddr, dstAddr);
+                                               BaseAtom* target = ((BaseAtom*)&(ref->getTarget()));
+                                               if ( target != NULL )
+                                                       target->alignAtLeast(2);
+                                       }
+                               }
+                               break;
+                       case PPC_RELOC_HI16:
+                               {
+                                       if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
+                                               printf("PPC_RELOC_HI16 missing following pair\n");
+                                               break;
+                                       }
+                                       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);
+                                               makeReference(A::kAbsHigh16, srcAddr, dstAddr);
+                                       }
+                               }
+                               break;
+                       case PPC_RELOC_HA16:
+                               {
+                                       if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
+                                               printf("PPC_RELOC_HA16 missing following pair\n");
+                                               break;
+                                       }
+                                       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;
+                                               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 {
+                                               makeReference(A::kPointer, srcAddr, pointerValue);
+                                       }
+                               }
+                               break;
+                       case PPC_RELOC_JBSR:
+                               // this is from -mlong-branch codegen.  We ignore the jump island
+                               if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
+                                       printf("PPC_RELOC_JBSR missing following pair\n");
+                                       break;
+                               }
+                               result = true;
+                               makeReference(A::kBranch24, srcAddr, nextReloc->r_address());
+                               break;
+                       default:
+                               printf("unknown relocation type %d\n", 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 ) {
+                                               printf("PPC_RELOC_LO16_SECTDIFF missing following PAIR\n");
+                                               break;
+                                       }
+                                       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 ) {
+                                               printf("PPC_RELOC_LO14_SECTDIFF missing following PAIR\n");
+                                               break;
+                                       }
+                                       instruction = BigEndian::get32(*fixUpPtr);
+                                       lowBits = (instruction & 0xFFFC);
+                                       displacement = (nextRelocAddress << 16) | ((uint32_t)lowBits & 0x0000FFFF);
+                                       Reference<A>* ref = makeReferenceWithToBase(A::kPICBaseLow14, srcAddr, nextRelocValue, nextRelocValue + displacement, dstAddr);
+                                       BaseAtom* target = ((BaseAtom*)&(ref->getTarget()));
+                                       if ( target != NULL ) // can be NULL if target is turned into by-name reference
+                                               target->alignAtLeast(2);
+                               }
+                               break;
+                       case PPC_RELOC_HA16_SECTDIFF:
+                               {
+                                       if ( ! nextRelocIsPair ) {
+                                               printf("PPC_RELOC_HA16_SECTDIFF missing following PAIR\n");
+                                               break;
+                                       }
+                                       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 ) {
+                                               printf("PPC_RELOC_LO14 missing following PAIR\n");
+                                               break;
+                                       }
+                                       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 ) {
+                                               printf("PPC_RELOC_LO16 missing following PAIR\n");
+                                               break;
+                                       }
+                                       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 ) {
+                                               printf("PPC_RELOC_HA16 missing following PAIR\n");
+                                               break;
+                                       }
+                                       instruction = BigEndian::get32(*fixUpPtr);
+                                       lowBits = (nextRelocAddress & 0xFFFF);
+                                       betterDstAddr = ((instruction & 0xFFFF) << 16) + (int32_t)lowBits;
+                                       makeReferenceWithToBase(A::kAbsHigh16AddLow, srcAddr, betterDstAddr, dstAddr);
+                               }
+                               break;
+                       case PPC_RELOC_SECTDIFF:
+                       case PPC_RELOC_LOCAL_SECTDIFF:
+                               {
+                                       if ( ! nextRelocIsPair ) {
+                                               printf("PPC_RELOC_SECTDIFF missing following pair\n");
+                                               break;
+                                       }
+                                       makeReference(pointerDiffKindForLength_powerpc(sreloc->r_length()), srcAddr, nextRelocValue, dstAddr);
+                               }
+                               break;
+                       case PPC_RELOC_PAIR:
+                               break;
+                       case PPC_RELOC_HI16_SECTDIFF:
+                               printf("unexpected scattered relocation type PPC_RELOC_HI16_SECTDIFF\n");
+                               break;
+                       default:
+                               printf("unknown scattered relocation type %d\n", sreloc->r_type());
+               }
+       }
+       return result;
+}
+
+template <>
+ppc::ReferenceKinds Reader<ppc>::pointerDiffKindForLength_powerpc(uint8_t r_length)
+{
+       if ( r_length == 2 )
+               return ppc::kPointerDiff32;
+       else
+               throw "bad diff relocations r_length for ppc architecture";
+ }
+
+template <>
+ppc64::ReferenceKinds Reader<ppc64>::pointerDiffKindForLength_powerpc(uint8_t r_length)
+{
+       if ( r_length == 2 )
+               return ppc64::kPointerDiff32;
+       else if ( r_length == 3 )
+               return ppc64::kPointerDiff64;
+       else
+               throw "bad diff relocations r_length for ppc64 architecture";
+ }
+
+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:
+                               {
+                                       if ( reloc->r_length() != 2 )
+                                               throw "bad vanilla relocation length";
+                                       x86::ReferenceKinds kind;
+                                       uint32_t pointerValue = E::get32(*fixUpPtr);
+                                       if ( reloc->r_pcrel() ) {
+                                               kind = x86::kPCRel32;
+                                               pointerValue += srcAddr + sizeof(uint32_t);
+                                       }
+                                       else {
+                                               kind = x86::kPointer;
+                                       }
+                                       if ( reloc->r_extern() ) {
+                                               const macho_nlist<P>* targetSymbol = &fSymbols[reloc->r_symbolnum()];
+                                               if ( this->isWeakImportSymbol(targetSymbol) )
+                                                       kind = x86::kPointerWeakImport;
+                                               const char* targetName = &fStrings[targetSymbol->n_strx()];
+                                               makeByNameReference(kind, srcAddr, targetName, pointerValue);
+                                       }
+                                       else {
+                                               // 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(pointerValue).atom;
+                                               if ( reloc->r_pcrel() && (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn)
+                                                       && ((AnonymousAtom<x86>*)atom)->isWeakImportStub() )
+                                                       makeReference(x86::kPCRel32WeakImport, srcAddr, pointerValue);
+                                               else
+                                                       makeReference(kind, srcAddr, pointerValue);
+                                       }
+                               }
+                               break;
+                       default:
+                               printf("unknown relocation type %d\n", 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() == 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();
+                       }
+               }
+               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() ) {
+                                               betterDstAddr += srcAddr + 4;
+                                               makeReferenceWithToBase(x86::kPCRel32, srcAddr, betterDstAddr, dstAddr);
+                                       }
+                                       else {
+                                               makeReferenceWithToBase(x86::kPointer, srcAddr, betterDstAddr, dstAddr);
+                                       }
+                               break;
+                       case GENERIC_RELOC_SECTDIFF:
+                       case GENERIC_RELOC_LOCAL_SECTDIFF:
+                               {
+                                       if ( !nextRelocIsPair ) {
+                                               printf("GENERIC_RELOC_SECTDIFF missing following pair\n");
+                                               break;
+                                       }
+                                       if ( sreloc->r_length() != 2 )
+                                               throw "bad length for GENERIC_RELOC_SECTDIFF";
+                                       betterDstAddr = LittleEndian::get32(*fixUpPtr);
+                                       makeReferenceWithToBase(x86::kPointerDiff, srcAddr, nextRelocValue, betterDstAddr+nextRelocValue, dstAddr);
+                               }
+                               break;
+                       case GENERIC_RELOC_PAIR:
+                               // do nothing, already used via a look ahead
+                               break;
+                       default:
+                               printf("unknown scattered relocation type %d\n", sreloc->r_type());
+               }
+       }
+       return result;
+}
+
+
+
+template <>
+const char* Reference<x86>::getDescription() const
+{
+       static char temp[1024];
+       switch( fKind ) {
+               case x86::kNoFixUp:
+                       sprintf(temp, "reference to ");
+                       break;
+               case x86::kFollowOn:
+                       sprintf(temp, "followed by ");
+                       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->getTargetName(), targetQuotes, fToTarget.offset,
+                                                          fromQuotes, this->getFromTargetName(), 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;
+       }
+       // 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[1024];
+       switch( fKind ) {
+               case ppc::kNoFixUp:
+                       sprintf(temp, "reference to ");
+                       break;
+               case ppc::kFollowOn:
+                       sprintf(temp, "followed by ");
+                       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::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->getTargetName(), targetQuotes, fToTarget.offset,
+                                                          fromQuotes, this->getFromTargetName(), 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 offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
+                       break;
+               case ppc::kPICBaseLow14:
+                       sprintf(temp, "offset 0x%04X, low  14 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, fFromTarget.offset);
+                       break;
+               case ppc::kPICBaseHigh16:
+                       sprintf(temp, "offset 0x%04X, high 16 fixup from pic-base offset 0x%04X to ", fFixUpOffsetInSrc, 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 to absolute address of ", fFixUpOffsetInSrc);
+                       break;
+               case ppc::kAbsHigh16AddLow:
+                       sprintf(temp, "offset 0x%04X, high 16 fixup to absolute address of ", 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[1024];
+       switch( fKind ) {
+               case ppc64::kNoFixUp:
+                       sprintf(temp, "reference to ");
+                       break;
+               case ppc64::kFollowOn:
+                       sprintf(temp, "followed by ");
+                       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->getTargetName(), targetQuotes, fToTarget.offset,
+                                                          fromQuotes, this->getFromTargetName(), 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->getTargetName(), targetQuotes, fToTarget.offset,
+                                                          fromQuotes, this->getFromTargetName(), 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 to absolute address of ", fFixUpOffsetInSrc);
+                       break;
+               case ppc64::kAbsHigh16AddLow:
+                       sprintf(temp, "offset 0x%04llX, high 16 fixup to absolute address of ", 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;
+}
+
+
+
+
+}; // namespace relocatable
+}; // namespace mach_o
+
+#endif // __OBJECT_FILE_MACH_O__
diff --git a/src/MachOWriterExecutable.hpp b/src/MachOWriterExecutable.hpp
new file mode 100644 (file)
index 0000000..30aa24b
--- /dev/null
@@ -0,0 +1,4574 @@
+/* -*- 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 __EXECUTABLE_MACH_O__
+#define __EXECUTABLE_MACH_O__
+
+#include <stdint.h>
+#include <stddef.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <mach-o/loader.h>
+#include <mach-o/nlist.h>
+#include <mach-o/reloc.h>
+//#include <mach-o/ppc/reloc.h>
+#include <mach-o/stab.h>
+#include <uuid/uuid.h>
+#include <mach/i386/thread_status.h>
+#include <mach/ppc/thread_status.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"
+
+
+//
+//
+//     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>::stubableReferenceKind()
+//                     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 SymbolTableLoadCommandsAtom;
+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 LocalRelocationsLinkEditAtom;
+template <typename A> class ExternalRelocationsLinkEditAtom;
+template <typename A> class SymbolTableLinkEditAtom;
+template <typename A> class IndirectTableLinkEditAtom;
+template <typename A> class StringsLinkEditAtom;
+template <typename A> class LoadCommandsPaddingAtom;
+template <typename A> class StubAtom;
+template <typename A> class StubHelperAtom;
+template <typename A> class LazyPointerAtom;
+template <typename A> class NonLazyPointerAtom;
+
+
+// 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), fAllNonLazyPointers(false), fAllStubs(false),
+                                                                                                               fAllSelfModifyingStubs(false), fAllZeroFill(false), fVirtualSection(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                                                            fAllNonLazyPointers;
+       bool                                                            fAllStubs;
+       bool                                                            fAllSelfModifyingStubs;
+       bool                                                            fAllZeroFill;
+       bool                                                            fVirtualSection;
+};
+
+// 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() : fInitProtection(0), fMaxProtection(0), fFileOffset(0), fFileSize(0),
+                                                                                                               fBaseAddress(0), fSize(0), fFixedAddress(false) { 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;
+       bool                                                            fFixedAddress;
+};
+
+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 class ObjectFile::Atom*                                 getUndefinedProxyAtom(const char* name);
+       virtual uint64_t                                                                write(std::vector<class ObjectFile::Atom*>& atoms,
+                                                                                                                 std::vector<class ObjectFile::Reader::Stab>& stabs,
+                                                                                                                 class ObjectFile::Atom* entryPointAtom,
+                                                                                                                 class ObjectFile::Atom* dyldHelperAtom,
+                                                                                                                 bool createUUID);
+
+private:
+       typedef typename A::P                   P;
+       typedef typename A::P::uint_t   pint_t;
+
+       enum RelocKind { kRelocNone, kRelocInternal, kRelocExternal };
+
+       void                                            assignFileOffsets();
+       void                                            synthesizeStubs();
+       void                                            partitionIntoSections();
+       bool                                            addBranchIslands();
+       bool                                            addPPCBranchIslands();
+       uint8_t                                         branch24Reference();
+       void                                            adjustLoadCommandsAndPadding();
+       void                                            createDynamicLinkerCommand();
+       void                                            createDylibCommands();
+       void                                            buildLinkEdit();
+       uint64_t                                        writeAtoms();
+       void                                            writeNoOps(uint32_t from, uint32_t to);
+       void                                            collectExportedAndImportedAndLocalAtoms();
+       void                                            setNlistRange(std::vector<class ObjectFile::Atom*>& atoms, uint32_t startIndex, uint32_t count);
+       void                                            buildSymbolTable();
+       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);
+       uint64_t                                        getAtomLoadAddress(const ObjectFile::Atom* atom);
+       uint8_t                                         ordinalForLibrary(ObjectFile::Reader* file);
+       bool                                            shouldExport(const ObjectFile::Atom& atom) const;
+       void                                            buildFixups();
+       void                                            adjustLinkEditSections();
+       void                                            buildObjectFileFixups();
+       void                                            buildExecutableFixups();
+       bool                                            referenceRequiresRuntimeFixUp(const ObjectFile::Reference* ref, bool slideable) 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);
+       uint32_t                                        addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref);
+       uint32_t                                        addObjectRelocs_powerpc(ObjectFile::Atom* atom, ObjectFile::Reference* ref);
+       uint8_t                                         getRelocPointerSize();
+       bool                                            stubableReferenceKind(uint8_t kind);
+       bool                                            GOTReferenceKind(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(uint8_t kind, bool slideable);
+
+
+       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 SymbolTableLoadCommandsAtom<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 LocalRelocationsLinkEditAtom<A>;
+       friend class ExternalRelocationsLinkEditAtom<A>;
+       friend class SymbolTableLinkEditAtom<A>;
+//     friend class IndirectTableLinkEditAtom<A>;
+       friend class StringsLinkEditAtom<A>;
+       friend class LoadCommandsPaddingAtom<A>;
+       friend class StubAtom<A>;
+       friend class StubHelperAtom<A>;
+       friend class LazyPointerAtom<A>;
+       friend class NonLazyPointerAtom<A>;
+
+       const char*                                                                             fFilePath;
+       Options&                                                                                fOptions;
+       int                                                                                             fFileDescriptor;
+       std::vector<class ObjectFile::Atom*>*                   fAllAtoms;
+       std::vector<class ObjectFile::Reader::Stab>*    fStabs;
+       class SectionInfo*                                                              fLoadCommandsSection;
+       class SegmentInfo*                                                              fLoadCommandsSegment;
+       class SegmentLoadCommandsAtom<A>*                               fSegmentCommands;
+       class SymbolTableLoadCommandsAtom<A>*                   fSymbolTableCommands;
+       class LoadCommandsPaddingAtom<A>*                               fHeaderPadding;
+       class UUIDLoadCommandAtom<A>*                               fUUIDAtom;
+       std::vector<class ObjectFile::Atom*>                    fWriterSynthesizedAtoms;
+       std::vector<SegmentInfo*>                                               fSegmentInfos;
+       class ObjectFile::Atom*                                                 fEntryPoint;
+       class ObjectFile::Atom*                                                 fDyldHelper;
+       std::vector<DirectLibrary>                                              fDirectLibraries;
+       std::map<class ObjectFile::Reader*, uint32_t>   fLibraryToOrdinal;
+       std::vector<class ObjectFile::Atom*>                    fExportedAtoms;
+       std::vector<class ObjectFile::Atom*>                    fImportedAtoms;
+       std::vector<class ObjectFile::Atom*>                    fLocalSymbolAtoms;
+       class SectionRelocationsLinkEditAtom<A>*                fSectionRelocationsAtom;
+       class LocalRelocationsLinkEditAtom<A>*                  fLocalRelocationsAtom;
+       class ExternalRelocationsLinkEditAtom<A>*               fExternalRelocationsAtom;
+       class SymbolTableLinkEditAtom<A>*                               fSymbolTableAtom;
+       class IndirectTableLinkEditAtom<A>*                             fIndirectTableAtom;
+       class StringsLinkEditAtom<A>*                                   fStringsAtom;
+       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::map<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 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;
+       bool                                                                                    fEmitVirtualSections;
+       bool                                                                                    fHasWeakExports;
+       bool                                                                                    fReferencesWeakImports;
+       bool                                                                                    fSeenFollowOnReferences;
+       std::map<const ObjectFile::Atom*,bool>                  fWeakImportMap;
+};
+
+
+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                                                          fgDataSegment;
+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::fgDataSegment("__DATA", true, true, false, 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) { setDontDeadStrip(); }
+
+       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                                                    isZeroFill() 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 bool                                                    requiresFollowOnAtom() const    { return false; }
+       virtual ObjectFile::Atom&                               getFollowOnAtom() const                 { return *((ObjectFile::Atom*)NULL); }
+       virtual std::vector<ObjectFile::LineInfo>*      getLineInfo() const                     { return NULL; }
+       virtual uint8_t                                                 getAlignment() const                    { return 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 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) {}
+       virtual const char*                                             getDisplayName() const  { return "page zero content"; }
+       virtual bool                                                    isZeroFill() const              { return true; }
+       virtual uint64_t                                                getSize() const                 { return fWriter.fOptions.zeroPageSize(); }
+       virtual const char*                                             getSectionName() const  { return "._zeropage"; }
+       virtual uint8_t                                                 getAlignment() const    { return 12; }
+private:
+       using WriterAtom<A>::fWriter;
+       typedef typename A::P                                   P;
+};
+
+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 uint8_t                                                                 getAlignment() const            { return 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, Segment::fgTextSegment) {}
+       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 uint8_t                                                                 getAlignment() const            { return 12; }
+       virtual const char*                                                             getSectionName() const          { return "._mach_header"; }
+       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 uint8_t                                                 getAlignment() const    { return 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, Segment& segment) : WriterAtom<A>(writer, segment) {}
+       static uint64_t                                                 alignedSize(uint64_t size);
+};
+
+
+template <typename A>
+class SegmentLoadCommandsAtom : public LoadCommandAtom<A>
+{
+public:
+                                                                                       SegmentLoadCommandsAtom(Writer<A>& writer)  
+                                                                                               : LoadCommandAtom<A>(writer, Segment::fgTextSegment), fCommandCount(0), fSize(0) 
+                                                                                               { writer.fSegmentCommands = this; }
+       virtual const char*                                             getDisplayName() const  { return "segment load commands"; }
+       virtual uint64_t                                                getSize() const                 { return fSize; }
+       virtual uint8_t                                                 getAlignment() const    { return 2; }
+       virtual const char*                                             getSectionName() const  { return "._load_commands"; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
+
+       void                                                                    computeSize();
+       void                                                                    setup();
+       unsigned int                                                    commandCount()                  { return fCommandCount; }
+       void                                                                    assignFileOffsets();
+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 uint8_t                                                 getAlignment() const    { return 2; }
+       virtual const char*                                             getSectionName() const  { return "._load_commands"; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
+       unsigned int                                                    commandCount();
+
+private:
+       using WriterAtom<A>::fWriter;
+       typedef typename A::P                                   P;
+       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, Segment::fgTextSegment) {}
+       virtual const char*                                             getDisplayName() const { return "thread load commands"; }
+       virtual uint64_t                                                getSize() const;
+       virtual uint8_t                                                 getAlignment() const    { return 2; }
+       virtual const char*                                             getSectionName() const  { return "._load_commands"; }
+       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, Segment::fgTextSegment) {}
+       virtual const char*                                             getDisplayName() const  { return "dyld load command"; }
+       virtual uint64_t                                                getSize() const;
+       virtual uint8_t                                                 getAlignment() const    { return 2; }
+       virtual const char*                                             getSectionName() const  { return "._load_commands"; }
+       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, Segment::fgTextSegment), clientString(client) {}
+       virtual const char*                                                     getDisplayName() const  { return "allowable_client load command"; }
+       virtual uint64_t                                                        getSize() const;
+       virtual uint8_t                                                         getAlignment() const    { return 2; }
+       virtual const char*                                                     getSectionName() const  { return "._load_commands"; }
+       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, Segment::fgTextSegment), fInfo(info) {}
+       virtual const char*                                             getDisplayName() const  { return "dylib load command"; }
+       virtual uint64_t                                                getSize() const;
+       virtual uint8_t                                                 getAlignment() const    { return 2; }
+       virtual const char*                                             getSectionName() const  { return "._load_commands"; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
+private:
+       using WriterAtom<A>::fWriter;
+       typedef typename A::P                                   P;
+       ExecutableFile::DyLibUsed&                              fInfo;
+};
+
+template <typename A>
+class DylibIDLoadCommandsAtom : public LoadCommandAtom<A>
+{
+public:
+                                                                                       DylibIDLoadCommandsAtom(Writer<A>& writer) : LoadCommandAtom<A>(writer, Segment::fgTextSegment) {}
+       virtual const char*                                             getDisplayName() const { return "dylib ID load command"; }
+       virtual uint64_t                                                getSize() const;
+       virtual uint8_t                                                 getAlignment() const    { return 2; }
+       virtual const char*                                             getSectionName() const  { return "._load_commands"; }
+       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, Segment::fgTextSegment) {}
+       virtual const char*                                             getDisplayName() const { return "routines load command"; }
+       virtual uint64_t                                                getSize() const                 { return sizeof(macho_routines_command<typename A::P>); }
+       virtual uint8_t                                                 getAlignment() const    { return 2; }
+       virtual const char*                                             getSectionName() const  { return "._load_commands"; }
+       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, Segment::fgTextSegment), fName(name) {}
+       virtual const char*                                             getDisplayName() const  { return "sub-umbrella load command"; }
+       virtual uint64_t                                                getSize() const;
+       virtual uint8_t                                                 getAlignment() const    { return 2; }
+       virtual const char*                                             getSectionName() const  { return "._load_commands"; }
+       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, Segment::fgTextSegment), fNameStart(nameStart), fNameLength(nameLen) {}
+       virtual const char*                                             getDisplayName() const  { return "sub-library load command"; }
+       virtual uint64_t                                                getSize() const;
+       virtual uint8_t                                                 getAlignment() const    { return 2; }
+       virtual const char*                                             getSectionName() const  { return "._load_commands"; }
+       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, Segment::fgTextSegment), fName(name) {}
+       virtual const char*                                             getDisplayName() const  { return "umbrella load command"; }
+       virtual uint64_t                                                getSize() const;
+       virtual uint8_t                                                 getAlignment() const    { return 2; }
+       virtual const char*                                             getSectionName() const  { return "._load_commands"; }
+       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, Segment::fgTextSegment), fEmit(false) { ::uuid_generate_random(fUUID);}
+       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 uint8_t                                                 getAlignment() const    { return 2; }
+       virtual const char*                                             getSectionName() const  { return "._load_commands"; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
+       virtual void                                                emit()                                      { fEmit = true; }
+private:
+       using WriterAtom<A>::fWriter;
+       typedef typename A::P                                   P;
+       uuid_t                                                                  fUUID;
+       bool                                                                fEmit;
+};
+
+template <typename A>
+class LoadCommandsPaddingAtom : public WriterAtom<A>
+{
+public:
+                                                                                       LoadCommandsPaddingAtom(Writer<A>& writer)
+                                                                                                       : WriterAtom<A>(writer, Segment::fgTextSegment), fSize(0) {}
+       virtual const char*                                             getDisplayName() const  { return "header padding"; }
+       virtual uint64_t                                                getSize() const                 { return fSize; }
+       virtual uint8_t                                                 getAlignment() const    { return 2; }
+       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 LinkEditAtom : public WriterAtom<A>
+{
+public:
+                                                                                       LinkEditAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgLinkEditSegment) {}
+       uint64_t                                                                getFileOffset() const;
+private:
+       typedef typename A::P                                   P;
+};
+
+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 uint8_t                                                 getAlignment() const    { return 3; }
+       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 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 uint8_t                                                 getAlignment() const    { return 3; }
+       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 uint8_t                                                 getAlignment() const    { return 2; }
+       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 uint8_t                                                 getAlignment() const    { return 3; }
+       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 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 uint8_t                                                 getAlignment() const    { return 2; }
+       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;
+};
+
+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 uint8_t                                                 getAlignment() const    { return 2; }
+       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; }
+
+private:
+       using WriterAtom<A>::fWriter;
+       typedef typename A::P                                   P;
+       enum { kBufferSize = 0x01000000 };
+       class CStringComparor {
+       public:
+               bool operator()(const char* left, const char* right) const { return (strcmp(left, right) < 0); }
+       };
+       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, uint32_t targetOffset);
+       virtual const char*                                             getName() const                         { return fName; }
+       virtual ObjectFile::Atom::Scope                 getScope() const                        { return ObjectFile::Atom::scopeLinkageUnit; }
+       virtual uint64_t                                                getSize() const;
+       virtual const char*                                             getSectionName() const          { return "__text"; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const;
+private:
+       using WriterAtom<A>::fWriter;
+       const char*                                                             fName;
+       ObjectFile::Atom&                                               fTarget;
+       uint32_t                                                                fTargetOffset;
+};
+
+template <typename A>
+class StubAtom : public WriterAtom<A>
+{
+public:
+                                                                                       StubAtom(Writer<A>& writer, ObjectFile::Atom& target);
+       virtual const char*                                             getName() const                         { return fName; }
+       virtual ObjectFile::Atom::Scope                 getScope() const                        { return ObjectFile::Atom::scopeLinkageUnit; }
+       virtual uint8_t                                                 getAlignment() const            { return 2; }
+       virtual uint64_t                                                getSize() 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; }
+private:
+       static const char*                                              stubName(const char* importName);
+       bool                                                                    pic() const;
+       using WriterAtom<A>::fWriter;
+       const char*                                                             fName;
+       ObjectFile::Atom&                                               fTarget;
+       std::vector<ObjectFile::Reference*>             fReferences;
+};
+
+
+template <typename A>
+class LazyPointerAtom : public WriterAtom<A>
+{
+public:
+                                                                                       LazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target);
+       virtual const char*                                             getName() const                         { return fName; }
+       virtual ObjectFile::Atom::Scope                 getScope() const                        { return ObjectFile::Atom::scopeLinkageUnit; }
+       virtual uint64_t                                                getSize() const                         { return sizeof(typename A::P::uint_t); }
+       virtual const char*                                             getSectionName() const          { return "__la_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; }
+private:
+       using WriterAtom<A>::fWriter;
+       static const char*                                              lazyPointerName(const char* importName);
+       const char*                                                             fName;
+       ObjectFile::Atom&                                               fTarget;
+       std::vector<ObjectFile::Reference*>             fReferences;
+};
+
+
+template <typename A>
+class NonLazyPointerAtom : public WriterAtom<A>
+{
+public:
+                                                                                       NonLazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target);
+       virtual const char*                                             getName() const                         { return fName; }
+       virtual ObjectFile::Atom::Scope                 getScope() const                        { return ObjectFile::Atom::scopeLinkageUnit; }
+       virtual uint64_t                                                getSize() const                         { return sizeof(typename A::P::uint_t); }
+       virtual const char*                                             getSectionName() const          { return "__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; }
+private:
+       using WriterAtom<A>::fWriter;
+       static const char*                                              nonlazyPointerName(const char* importName);
+       const char*                                                             fName;
+       ObjectFile::Atom&                                               fTarget;
+       std::vector<ObjectFile::Reference*>             fReferences;
+};
+
+
+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),
+                                                                                       fTargetOffset(toOffset), fFromTarget(fromTarget), fFromTargetOffset(fromOffset) {}
+
+       virtual                                 ~WriterReference() {}
+
+       virtual bool                    isTargetUnbound() const                                                 { return false; }
+       virtual bool                    isFromTargetUnbound() const                                             { return false; }
+       virtual uint8_t                 getKind() const                                                                 { return (uint8_t)fKind; }
+       virtual uint64_t                getFixUpOffset() const                                                  { return fFixUpOffsetInSrc; }
+       virtual const char*             getTargetName() const                                                   { return fTarget->getName(); }
+       virtual ObjectFile::Atom& getTarget() const                                                             { return *fTarget; }
+       virtual uint64_t                getTargetOffset() const                                                 { return fTargetOffset; }
+       virtual bool                    hasFromTarget() const                                                   { return (fFromTarget != NULL); }
+       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 refrence"; }
+       virtual uint64_t                getFromTargetOffset() const                                             { return fFromTargetOffset; }
+
+private:
+       Kinds                                   fKind;
+       uint32_t                                fFixUpOffsetInSrc;
+       ObjectFile::Atom*               fTarget;
+       uint32_t                                fTargetOffset;
+       ObjectFile::Atom*               fFromTarget;
+       uint32_t                                fFromTargetOffset;
+};
+
+
+
+struct ExportSorter
+{
+     bool operator()(ObjectFile::Atom* left, ObjectFile::Atom* right)
+     {
+          return (strcmp(left->getName(), right->getName()) < 0);
+     }
+};
+
+
+
+
+template <typename A>
+Writer<A>::Writer(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries)
+       : ExecutableFile::Writer(dynamicLibraries), fFilePath(strdup(path)), fOptions(options), fLoadCommandsSection(NULL),
+         fLoadCommandsSegment(NULL), fLargestAtomSize(1),
+         fEmitVirtualSections(false), fHasWeakExports(false), fReferencesWeakImports(false),
+         fSeenFollowOnReferences(false)
+{
+       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 writeable 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);
+       fFileDescriptor = open(fFilePath, O_CREAT | O_WRONLY | O_TRUNC, permissions);
+       if ( fFileDescriptor == -1 ) {
+               throw "can't open file for writing";
+       }
+
+       switch ( fOptions.outputKind() ) {
+               case Options::kDynamicExecutable:
+               case Options::kStaticExecutable:
+                       fWriterSynthesizedAtoms.push_back(new PageZeroAtom<A>(*this));
+                       if ( fOptions.outputKind() == Options::kDynamicExecutable )
+                               fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
+                       fWriterSynthesizedAtoms.push_back(new MachHeaderAtom<A>(*this));
+                       fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<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(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::kDynamicLibrary:
+               case Options::kDynamicBundle:
+                       fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
+                       // fall through
+               case Options::kObjectFile:
+                       fWriterSynthesizedAtoms.push_back(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));
+                       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(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));
+                       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
+       uint8_t ordinal = 1;
+       switch ( fOptions.outputKind() ) {
+               case Options::kDynamicExecutable:
+               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];
+                                       if ( dylibInfo.indirect ) {
+                                               // find ordinal of direct reader
+                                               if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace ) {
+                                                       bool found = false;
+                                                       for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
+                                                               if ( it->first == dylibInfo.directReader ) {
+                                                                       //fprintf(stderr, "ordinal %d for indirect %s\n", it->second, dylibInfo.reader->getPath());
+                                                                       fLibraryToOrdinal[dylibInfo.reader] = it->second;
+                                                                       found = true;
+                                                                       break;
+                                                               }
+                                                       }
+                                                       if ( ! found )
+                                                               fprintf(stderr, "ld64 warning: ordinal not found for %s, parent %s\n", dylibInfo.reader->getPath(), dylibInfo.directReader != NULL ? dylibInfo.directReader->getPath() : NULL);
+                                               }
+                                       }
+                                       else {
+                                               // see if a DylibLoadCommandsAtom has already been created for this install path
+                                               bool newDylib = true;
+                                               const char* dylibInstallPath = dylibInfo.reader->getInstallPath();
+                                               if ( dylibInfo.options.fInstallPathOverride != NULL )
+                                                       dylibInstallPath = dylibInfo.options.fInstallPathOverride;
+                                               for (unsigned int seenLib=0; seenLib < i; ++seenLib) {
+                                                       ExecutableFile::DyLibUsed& seenDylibInfo = dynamicLibraries[seenLib];
+                                                       if ( !seenDylibInfo.indirect ) {
+                                                               const char* seenDylibInstallPath = seenDylibInfo.reader->getInstallPath();
+                                                               if ( seenDylibInfo.options.fInstallPathOverride != NULL )
+                                                                       seenDylibInstallPath = dylibInfo.options.fInstallPathOverride;
+                                                               if ( strcmp(seenDylibInstallPath, dylibInstallPath) == 0 ) {
+                                                                       fLibraryToOrdinal[dylibInfo.reader] = fLibraryToOrdinal[seenDylibInfo.reader];
+                                                                       newDylib = false;
+                                                                       break;
+                                                               }
+                                                       }
+                                               }
+
+                                               if ( newDylib ) {
+                                                       // assign new ordinal and check for other paired load commands
+                                                       fLibraryToOrdinal[dylibInfo.reader] = ordinal++;
+                                                       fWriterSynthesizedAtoms.push_back(new DylibLoadCommandsAtom<A>(*this, dylibInfo));
+                                                       if ( dylibInfo.options.fReExport ) {
+                                                               // 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()));
+                               }
+                               std::vector<const char*>& allowableClients = fOptions.allowableClients();
+                               if ( allowableClients.size() != 0 ) {
+                                       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:
+                       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;
+}
+
+
+template <typename A>
+ObjectFile::Atom* Writer<A>::getUndefinedProxyAtom(const char* name)
+{
+       if ( (fOptions.outputKind() == Options::kObjectFile)
+               || (fOptions.undefinedTreatment() != Options::kUndefinedError) )
+               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>
+uint64_t Writer<A>::write(std::vector<class ObjectFile::Atom*>& atoms,
+                                                 std::vector<class ObjectFile::Reader::Stab>& stabs,
+                                                 class ObjectFile::Atom* entryPointAtom, class ObjectFile::Atom* dyldHelperAtom,
+                                                 bool createUUID)
+{
+       fAllAtoms =  &atoms;
+       fStabs =  &stabs;
+       fEntryPoint = entryPointAtom;
+       fDyldHelper = dyldHelperAtom;
+
+       // Set for create UUID
+       if (createUUID)
+               fUUIDAtom->emit();
+
+       // create inter-library stubs
+       synthesizeStubs();
+
+       // 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();
+
+       // build symbol table and relocations
+       buildLinkEdit();
+
+       // write everything
+       return writeAtoms();
+}
+
+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 <typename A>
+void Writer<A>::setExportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
+{
+       // set n_type
+       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 ( (fOptions.outputKind() == Options::kDynamicExecutable) && (sectionIndex==0)
+               && (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip ))
+               entry->set_n_type(N_EXT | N_ABS);
+
+       // set n_desc
+       uint16_t desc = 0;
+       if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip )
+               desc |= REFERENCED_DYNAMICALLY;
+       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 )
+       entry->set_n_value(this->getAtomLoadAddress(atom));
+}
+
+template <typename A>
+void Writer<A>::setImportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
+{
+       // set n_type
+       entry->set_n_type(N_UNDF | N_EXT);
+       if ( fOptions.keepPrivateExterns()
+               && (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit)
+               && (fOptions.outputKind() == Options::kObjectFile) )
+               entry->set_n_type(N_UNDF | N_EXT | N_PEXT);
+
+       // 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 )
+               desc = REFERENCE_FLAG_UNDEFINED_LAZY; // FIXME
+               try {
+                       uint8_t ordinal = this->ordinalForLibrary(atom->getFile());
+                       SET_LIBRARY_ORDINAL(desc, ordinal);
+               }
+               catch (const char* msg) {
+                       throwf("%s %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath());
+               }
+       }
+       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_type
+       uint8_t type = N_SECT;
+       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->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition )
+               desc |= N_WEAK_DEF;
+       entry->set_n_desc(desc);
+
+       // 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));
+}
+
+
+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];
+               entry->set_n_strx(this->fStringsAtom->add(atom->getName()));
+               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>::buildSymbolTable()
+{
+       fSymbolTableStabsStartIndex             = 0;
+       fSymbolTableStabsCount                  = fStabs->size();
+       fSymbolTableLocalStartIndex             = fSymbolTableStabsStartIndex + fSymbolTableStabsCount;
+       fSymbolTableLocalCount                  = fLocalSymbolAtoms.size();
+       fSymbolTableExportStartIndex    = fSymbolTableLocalStartIndex + fSymbolTableLocalCount;
+       fSymbolTableExportCount                 = fExportedAtoms.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,  fSymbolTableLocalCount);
+       setNlistRange(fExportedAtoms,    fSymbolTableExportStartIndex, fSymbolTableExportCount);
+       setNlistRange(fImportedAtoms,    fSymbolTableImportStartIndex, fSymbolTableImportCount);
+       addStabs(fSymbolTableStabsStartIndex);
+}
+
+
+
+template <typename A>
+bool Writer<A>::shouldExport(const ObjectFile::Atom& atom) const
+{
+       if ( atom.getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn )
+               return false;
+       switch ( atom.getScope() ) {
+               case ObjectFile::Atom::scopeGlobal:
+                       return true;
+               case ObjectFile::Atom::scopeLinkageUnit:
+                       return ( (fOptions.outputKind() == Options::kObjectFile) && fOptions.keepPrivateExterns() );
+               default:
+                       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 (int i=0; i < atomCount; ++i) {
+               ObjectFile::Atom* atom = (*fAllAtoms)[i];
+               // only named atoms go in symbol table
+               if ( atom->getName() != NULL ) {
+                       // put atom into correct bucket: imports, exports, locals
+                       //printf("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 ) {
+                                               fImportedAtoms.push_back(atom);
+                                               break;
+                                       }
+                                       // else fall into
+                               case ObjectFile::Atom::kRegularDefinition:
+                               case ObjectFile::Atom::kWeakDefinition:
+                                       if ( this->shouldExport(*atom) )
+                                               fExportedAtoms.push_back(atom);
+                                       else if ( !fOptions.stripLocalSymbols()
+                                               && (atom->getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn) )
+                                               fLocalSymbolAtoms.push_back(atom);
+                                       break;
+                       }
+               }
+       }
+
+       // sort exported atoms by name
+       std::sort(fExportedAtoms.begin(), fExportedAtoms.end(), ExportSorter());
+       // sort imported atoms by name (not required by runtime, but helps make generated files binary diffable)
+       std::sort(fImportedAtoms.begin(), fImportedAtoms.end(), ExportSorter());
+}
+
+
+template <typename A>
+uint64_t Writer<A>::valueForStab(const ObjectFile::Reader::Stab& stab)
+{
+       switch ( stab.type ) {
+               case N_FUN:
+                       if ( stab.other == 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:
+                       return 0;
+               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)
+{
+       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)
+{
+       // search imports
+       int i = 0;
+       for(std::vector<ObjectFile::Atom*>::iterator it=fImportedAtoms.begin(); it != fImportedAtoms.end(); ++it) {
+               if ( &atom == *it )
+                       return i + fSymbolTableImportStartIndex;
+               ++i;
+       }
+
+       // search locals
+       i = 0;
+       for(std::vector<ObjectFile::Atom*>::iterator it=fLocalSymbolAtoms.begin(); it != fLocalSymbolAtoms.end(); ++it) {
+               if ( &atom == *it )
+                       return i + fSymbolTableLocalStartIndex;
+               ++i;
+       }
+
+       // search exports
+       i = 0;
+       for(std::vector<ObjectFile::Atom*>::iterator it=fExportedAtoms.begin(); it != fExportedAtoms.end(); ++it) {
+               if ( &atom == *it )
+                       return i + fSymbolTableExportStartIndex;
+               ++i;
+       }
+
+       throwf("atom not found in symbolIndex(%s) for %s", atom.getDisplayName(), atom.getFile()->getPath());
+}
+
+
+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>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
+{
+       ObjectFile::Atom& target = ref->getTarget();
+       bool isExtern = false;
+       switch ( target.getDefinitionKind() ) {
+               case ObjectFile::Atom::kRegularDefinition:
+                       isExtern = false;
+                       break;
+               case ObjectFile::Atom::kWeakDefinition:
+               case ObjectFile::Atom::kTentativeDefinition:
+               case ObjectFile::Atom::kExternalDefinition:
+               case ObjectFile::Atom::kExternalWeakDefinition:
+                       isExtern = shouldExport(target);
+                       break;
+       }
+       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();
+
+       switch ( kind ) {
+               case x86::kNoFixUp:
+               case x86::kFollowOn:
+                       return 0;
+
+               case x86::kPointer:
+               case x86::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(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.insert(fSectionRelocs.begin(), reloc1);
+                       return 1;
+
+               case x86::kPointerDiff:
+                       {
+                               pint_t fromAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
+                               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(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(2);
+                               sreloc2->set_r_type(PPC_RELOC_PAIR);
+                               sreloc2->set_r_address(0);
+                               sreloc2->set_r_value(fromAddr);
+                               fSectionRelocs.insert(fSectionRelocs.begin(), reloc2);
+                               fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
+                               return 2;
+                       }
+
+               case x86::kPCRel32WeakImport:
+               case x86::kPCRel32:
+                       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(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(2);
+                               reloc1.set_r_extern(isExtern);
+                               reloc1.set_r_type(GENERIC_RELOC_VANILLA);
+                       }
+                       fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
+                       return 1;
+
+       }
+       return 0;
+}
+
+
+
+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 = false;
+       switch ( target.getDefinitionKind() ) {
+               case ObjectFile::Atom::kRegularDefinition:
+                       isExtern = false;
+                       break;
+               case ObjectFile::Atom::kWeakDefinition:
+               case ObjectFile::Atom::kTentativeDefinition:
+               case ObjectFile::Atom::kExternalDefinition:
+               case ObjectFile::Atom::kExternalWeakDefinition:
+                       isExtern = shouldExport(target);
+                       break;
+       }
+       
+       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:
+                       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.insert(fSectionRelocs.begin(), reloc1);
+                       return 1;
+
+               case A::kPointerDiff32:
+               case A::kPointerDiff64:
+                       {
+                               pint_t toAddr = target.getAddress() + ref->getTargetOffset();
+                               pint_t fromAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
+                               sreloc1->set_r_scattered(true);
+                               sreloc1->set_r_pcrel(false);
+                               sreloc1->set_r_length( (kind == A::kPointerDiff32) ? 2 : 3);
+                               sreloc1->set_r_type(ref->getTargetOffset() != 0 ? PPC_RELOC_LOCAL_SECTDIFF : PPC_RELOC_SECTDIFF);
+                               sreloc1->set_r_address(address);
+                               sreloc1->set_r_value(toAddr);
+                               sreloc2->set_r_scattered(true);
+                               sreloc2->set_r_pcrel(false);
+                               sreloc2->set_r_length( (kind == A::kPointerDiff32) ? 2 : 3);
+                               sreloc2->set_r_type(PPC_RELOC_PAIR);
+                               sreloc2->set_r_address(0);
+                               sreloc2->set_r_value(fromAddr);
+                               fSectionRelocs.insert(fSectionRelocs.begin(), reloc2);
+                               fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
+                               return 2;
+                       }
+
+               case A::kBranch24WeakImport:
+               case A::kBranch24:
+                       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.insert(fSectionRelocs.begin(), 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.insert(fSectionRelocs.begin(), 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));
+                               sreloc2->set_r_value(fromAddr);
+                               fSectionRelocs.insert(fSectionRelocs.begin(), reloc2);
+                               fSectionRelocs.insert(fSectionRelocs.begin(), 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.insert(fSectionRelocs.begin(), reloc2);
+                               fSectionRelocs.insert(fSectionRelocs.begin(), 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.insert(fSectionRelocs.begin(), reloc2);
+                               fSectionRelocs.insert(fSectionRelocs.begin(), 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.insert(fSectionRelocs.begin(), reloc2);
+                               fSectionRelocs.insert(fSectionRelocs.begin(), 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.insert(fSectionRelocs.begin(), reloc2);
+                               fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
+                               return 2;
+                       }
+
+       }
+       return 0;
+}
+
+
+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->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\n", atom->getDisplayName());
+                                       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 ( ref->getKind() == A::kFollowOn )
+                                                       fSeenFollowOnReferences = true;
+                                               if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || 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
+                                                                        && (ref->getTarget().getScope() == ObjectFile::Atom::scopeLinkageUnit)
+                                                                        && !fOptions.keepPrivateExterns() )
+                                                                       undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
+                                                               else
+                                                                       undefinedSymbolIndex = this->symbolIndex(ref->getTarget());
+                                                       }
+                                                       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 ) {
+                                                                       fprintf(stderr, "lazy pointer %s missing initial binding\n", 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.insert(fSectionRelocs.begin(), reloc1);
+                                                                       ++relocIndex;
+                                                               }
+                                                       }
+                                                       else if ( curSection->fAllStubs ) {
+                                                               relocIndex += this->addObjectRelocs(atom, ref);
+                                                       }
+                                               }
+                                               else {
+                                                       relocIndex += this->addObjectRelocs(atom, ref);
+                                               }
+                                       }
+                               }
+                               curSection->fRelocCount = relocIndex - curSection->fRelocOffset;
+                       }
+               }
+       }
+
+       // now reverse reloc entries
+       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 <>
+bool Writer<ppc>::illegalRelocInFinalLinkedImage(uint8_t kind, bool slideable)
+{
+       switch ( kind ) {
+               case ppc::kAbsLow16:
+               case ppc::kAbsLow14:
+               case ppc::kAbsHigh16:
+               case ppc::kAbsHigh16AddLow:
+                       if ( slideable )
+                               return true;
+       }
+       return false;
+}
+
+
+template <>
+bool Writer<ppc64>::illegalRelocInFinalLinkedImage(uint8_t kind, bool slideable)
+{
+       switch ( kind ) {
+               case ppc::kAbsLow16:
+               case ppc::kAbsLow14:
+               case ppc::kAbsHigh16:
+               case ppc::kAbsHigh16AddLow:
+                       if ( slideable )
+                               return true;
+       }
+       return false;
+}
+
+template <>
+bool Writer<x86>::illegalRelocInFinalLinkedImage(uint8_t kind, bool slideable)
+{
+       return false;
+}
+
+
+
+template <typename A>
+typename Writer<A>::RelocKind Writer<A>::relocationNeededInFinalLinkedImage(const ObjectFile::Atom& target) const
+{
+       const bool slideable = (fOptions.outputKind() != Options::kDynamicExecutable) && (fOptions.outputKind() != Options::kStaticExecutable);
+
+       switch ( target.getDefinitionKind() ) {
+               case ObjectFile::Atom::kTentativeDefinition:
+               case ObjectFile::Atom::kRegularDefinition:
+                       // for flat-namespace or interposable two-level-namespace
+                       // all references to exported symbols get indirected
+                       if ( this->shouldExport(target) &&
+                               ((fOptions.nameSpace() == Options::kFlatNameSpace)
+                         || (fOptions.nameSpace() == Options::kForceFlatNameSpace)
+                         || fOptions.interposable()) )
+                               return kRelocExternal;
+                       else if ( slideable )
+                               return kRelocInternal;
+                       else
+                               return kRelocNone;
+               case ObjectFile::Atom::kWeakDefinition:
+                       // all calls to global weak definitions get indirected
+                       if ( this->shouldExport(target) )
+                               return kRelocExternal;
+                       else if ( slideable )
+                               return kRelocInternal;
+                       else
+                               return kRelocNone;
+               case ObjectFile::Atom::kExternalDefinition:
+               case ObjectFile::Atom::kExternalWeakDefinition:
+                       return kRelocExternal;
+       }
+       return kRelocNone;
+}
+
+template <typename A>
+void Writer<A>::buildExecutableFixups()
+{
+       const bool slideable = (fOptions.outputKind() != Options::kDynamicExecutable) && (fOptions.outputKind() != Options::kStaticExecutable);
+       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 %p\n", curSection->fSectionName);
+                       std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
+                       if ( ! curSection->fAllZeroFill ) {
+                               if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers || curSection->fAllStubs || curSection->fAllSelfModifyingStubs )
+                                       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());
+                                       for (int l=0; l < refCount; ++l) {
+                                               ObjectFile::Reference* ref = refs[l];
+                                               if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers ) {
+                                                       // if atom is in (non)lazy_pointer section, this is encoded as an indirect symbol
+                                                       if ( atom->getSize() != sizeof(pint_t) ) {
+                                                               printf("wrong size pointer atom %s from file %s\n", atom->getDisplayName(), atom->getFile()->getPath());
+                                                       }
+                                                       ObjectFile::Atom* pointerTarget = &(ref->getTarget());
+                                                       if ( curSection->fAllLazyPointers ) {
+                                                               pointerTarget = ((LazyPointerAtom<A>*)atom)->getTarget();
+                                                       }
+                                                       uint32_t offsetInSection = atom->getSectionOffset();
+                                                       uint32_t indexInSection = offsetInSection / sizeof(pint_t);
+                                                       uint32_t undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
+                                                       if ( this->relocationNeededInFinalLinkedImage(*pointerTarget) == kRelocExternal )
+                                                               undefinedSymbolIndex = this->symbolIndex(*pointerTarget);
+                                                       uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
+                                                       IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
+                                                       //fprintf(stderr,"fIndirectTableAtom->fTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, ref->getTarget().getName(), atom->getSize());
+                                                       fIndirectTableAtom->fTable.push_back(entry);
+                                                       if ( slideable && curSection->fAllLazyPointers ) {
+                                                               // if this is a dylib/bundle, need vanilla internal relocation to fix up binding handler if image slides
+                                                               macho_relocation_info<P> pblaReloc;
+                                                               uint32_t sectionNum = 1;
+                                                               if ( fDyldHelper != NULL )
+                                                                       sectionNum = ((SectionInfo*)(fDyldHelper->getSection()))->getIndex();
+                                                               //fprintf(stderr, "lazy pointer reloc, section index=%u, section name=%s\n", sectionNum, curSection->fSectionName);
+                                                               pblaReloc.set_r_address(atom->getAddress()-fOptions.baseAddress());
+                                                               pblaReloc.set_r_symbolnum(sectionNum);
+                                                               pblaReloc.set_r_pcrel(false);
+                                                               pblaReloc.set_r_length();
+                                                               pblaReloc.set_r_extern(false);
+                                                               pblaReloc.set_r_type(GENERIC_RELOC_VANILLA);
+                                                               fInternalRelocs.push_back(pblaReloc);
+                                                       }
+                                               }
+                                               else if ( ref->getKind() == A::kPointer ) {
+                                                       if ( slideable && ((curSegment->fInitProtection & VM_PROT_WRITE) == 0) ) {
+                                                               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(atom->getAddress()+ref->getFixUpOffset()-fOptions.baseAddress());
+                                                                               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);
+                                                                       }
+                                                                       break;
+                                                               case kRelocExternal:
+                                                                       {
+                                                                               macho_relocation_info<P> externalReloc;
+                                                                               externalReloc.set_r_address(atom->getAddress()+ref->getFixUpOffset()-fOptions.baseAddress());
+                                                                               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);
+                                                                       }
+                                                                       break;
+                                                       }
+                                               }
+                                               else if ( this->illegalRelocInFinalLinkedImage(ref->getKind(), slideable) ) {
+                                                       throwf("absolute addressing (perhaps -mdynamic-no-pic) used in %s from %s not allowed in slidable image", atom->getDisplayName(), atom->getFile()->getPath());
+                                               }
+                                       }
+                                       if ( curSection->fAllSelfModifyingStubs || curSection->fAllStubs ) {
+                                               ObjectFile::Atom* stubTarget = ((StubAtom<A>*)atom)->getTarget();
+                                               uint32_t undefinedSymbolIndex = this->symbolIndex(*stubTarget);
+                                               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);
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+
+template <>
+void Writer<ppc>::writeNoOps(uint32_t from, uint32_t to)
+{
+       uint32_t ppcNop;
+       OSWriteBigInt32(&ppcNop, 0, 0x60000000);
+       for (uint32_t p=from; p < to; p += 4)
+               ::pwrite(fFileDescriptor, &ppcNop, 4, p);
+}
+
+template <>
+void Writer<ppc64>::writeNoOps(uint32_t from, uint32_t to)
+{
+       uint32_t ppcNop;
+       OSWriteBigInt32(&ppcNop, 0, 0x60000000);
+       for (uint32_t p=from; p < to; p += 4)
+               ::pwrite(fFileDescriptor, &ppcNop, 4, p);
+}
+
+template <>
+void Writer<x86>::writeNoOps(uint32_t from, uint32_t to)
+{
+       uint8_t x86Nop = 0x90;
+       for (uint32_t p=from; p < to; ++p)
+               ::pwrite(fFileDescriptor, &x86Nop, 1, p);
+}
+
+
+template <typename A>
+uint64_t Writer<A>::writeAtoms()
+{
+       uint32_t end = 0;
+       uint8_t* buffer = new uint8_t[(fLargestAtomSize+4095) & (-4096)];
+       std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
+       const int segCount = segmentInfos.size();
+       for(int i=0; i < segCount; ++i) {
+               SegmentInfo* curSegment = segmentInfos[i];
+               bool isTextSeg = ((curSegment->fInitProtection & VM_PROT_EXECUTE) != 0);
+               std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
+               const int sectionCount = sectionInfos.size();
+               for(int j=0; j < sectionCount; ++j) {
+                       SectionInfo* curSection = sectionInfos[j];
+                       std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
+                       //printf("writing with max atom size 0x%X\n", fLargestAtomSize);
+                       //fprintf(stderr, "writing %d atoms for section %s\n", (int)sectionAtoms.size(), curSection->fSectionName);
+                       if ( ! curSection->fAllZeroFill ) {
+                               const int atomCount = sectionAtoms.size();
+                               end = curSection->fFileOffset;
+                               bool needsNops = isTextSeg && (strcmp(curSection->fSectionName, "__cstring") != 0);
+                               for (int k=0; k < atomCount; ++k) {
+                                       ObjectFile::Atom* atom = sectionAtoms[k];
+                                       if ( (atom->getDefinitionKind() != ObjectFile::Atom::kExternalDefinition)
+                                         && (atom->getDefinitionKind() != ObjectFile::Atom::kExternalWeakDefinition) ) {
+                                               uint32_t offset = curSection->fFileOffset + atom->getSectionOffset();
+                                               if ( offset != end ) {
+                                                       if ( needsNops ) {
+                                                               // fill gaps with no-ops
+                                                               writeNoOps(end, offset);
+                                                       }
+                                                       else {
+                                                               // zero fill gaps
+                                                               if ( (offset-end) == 4 ) {
+                                                                       uint32_t zero = 0;
+                                                                       ::pwrite(fFileDescriptor, &zero, 4, end);
+                                                               }
+                                                               else {
+                                                                       uint8_t zero = 0x00;
+                                                                       for (uint32_t p=end; p < offset; ++p)
+                                                                               ::pwrite(fFileDescriptor, &zero, 1, p);
+                                                               }
+                                                       }
+                                               }
+                                               uint64_t atomSize = atom->getSize();
+                                               if ( atomSize > fLargestAtomSize ) {
+                                                       throwf("ld64 internal error: atom \"%s\"is larger than expected 0x%X > 0x%llX", 
+                                                               atom->getDisplayName(), atomSize, fLargestAtomSize);
+                                               }
+                                               end = offset+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 %s\n", offset, end, atom->getAddress(), atom->getSize(), atom->getDisplayName());
+                                               // write out
+                                               ::pwrite(fFileDescriptor, buffer, atom->getSize(), offset);
+                                       }
+                               }
+                       }
+               }
+       }
+       delete [] buffer;
+       return end;
+}
+
+
+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()];
+       switch ( (x86::ReferenceKinds)(ref->getKind()) ) {
+               case x86::kNoFixUp:
+               case x86::kFollowOn:
+                       // do nothing
+                       break;
+               case x86::kPointerWeakImport:
+               case x86::kPointer:
+                       {
+                               if ( ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kRegularDefinition ) {
+                                       // external realocation ==> pointer contains addend
+                                       LittleEndian::set32(*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::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
+                               }
+                       }
+                       break;
+               case x86::kPointerDiff:
+                               LittleEndian::set32(*fixUp,
+                                       (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
+                       break;
+               case x86::kPCRel32WeakImport:
+               case x86::kPCRel32:
+                       int64_t 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;
+                       }
+                       const int64_t bl_twoGigLimit = 0x7FFFFFFF;
+                       if ( (displacement > bl_twoGigLimit) || (displacement < (-bl_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(*fixUp, (int32_t)displacement);
+                       break;
+       }
+}
+
+template <>
+void Writer<x86>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
+{
+       uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
+       bool isExternal = ( (ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kRegularDefinition)
+                                               && shouldExport(ref->getTarget()) );
+       switch (ref->getKind()) {
+               case x86::kNoFixUp:
+               case x86::kFollowOn:
+                       // do nothing
+                       break;
+               case x86::kPointer:
+                       {
+                               if ( isExternal ) {
+                                       // external realocation ==> pointer contains addend
+                                       LittleEndian::set32(*fixUp, ref->getTargetOffset());
+                               }
+                               else {
+                                       // internal relocation
+                                       if ( ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kTentativeDefinition ) {
+                                               // pointer contains target address
+                                               LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
+                                       }
+                                       else {
+                                               // pointer contains addend
+                                               LittleEndian::set32(*fixUp, ref->getTargetOffset());
+                                       }
+                               }
+                       }
+                       break;
+               case x86::kPointerDiff:
+                               LittleEndian::set32(*fixUp,
+                                       (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
+                       break;
+               case x86::kPCRel32:
+                       int64_t displacement = 0;
+                       if ( isExternal )
+                               displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
+                       else
+                               displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
+                       const int64_t bl_twoGigLimit = 0x7FFFFFFF;
+                       if ( (displacement > bl_twoGigLimit) || (displacement < (-bl_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(*fixUp, (int32_t)displacement);
+                       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 = ref->getTarget().getAddress() + ref->getTargetOffset();
+       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;
+
+       if ( finalLinkedImage )
+               relocateableExternal = (relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal);
+       else
+               relocateableExternal = ( (ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kRegularDefinition)
+                                                                       && shouldExport(ref->getTarget()) );
+
+       const int64_t picbase_twoGigLimit = 0x80000000;
+
+       switch ( (typename A::ReferenceKinds)(ref->getKind()) ) {
+               case A::kNoFixUp:
+               case A::kFollowOn:
+                       // 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 ) {
+                                       // lazy-symbol ==> pointer contains address of dyld_stub_binding_helper (stored in "from" target)
+                                       if ( fDyldHelper == NULL )
+                                               throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
+                                       P::setP(*fixUpPointer, fDyldHelper->getAddress());
+                               }
+                               else if ( relocateableExternal ) {
+                                       // external realocation ==> 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", target.getDisplayName(), target.getAddress());
+                                               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::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 in %s to %s in %s",
+                                                       displacement, inAtom->getDisplayName(), inAtom->getFile()->getPath(),
+                                                       ref->getTarget().getDisplayName(), 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:
+                       {
+                               //fprintf(stderr, "bc fixup %p to %s+0x%08X == 0x%08llX\n", this, ref->getTarget().getDisplayName(), ref->getTargetOffset(), targetAddr);
+                               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 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("bc 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, "bc 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 = inAtom->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 = inAtom->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 = inAtom->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 )
+                               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 )
+                               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 )
+                               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 )
+                               targetAddr -= ref->getTarget().getAddress();
+                       if ( targetAddr & 0x00008000 )
+                               targetAddr += 0x00010000;
+                       instruction = BigEndian::get32(*fixUp);
+                       newInstruction = (instruction & 0xFFFF0000) | (targetAddr >> 16);
+                       BigEndian::set32(*fixUp, newInstruction);
+                       break;
+       }
+}
+
+template <>
+bool Writer<ppc>::stubableReferenceKind(uint8_t kind)
+{
+       return (kind == ppc::kBranch24 || kind == ppc::kBranch24WeakImport);
+}
+
+template <>
+bool Writer<ppc64>::stubableReferenceKind(uint8_t kind)
+{
+       return (kind == ppc64::kBranch24 || kind == ppc64::kBranch24WeakImport);
+}
+
+template <>
+bool Writer<x86>::stubableReferenceKind(uint8_t kind)
+{
+       return (kind == x86::kPCRel32 || kind == x86::kPCRel32WeakImport);
+}
+
+
+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<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 <typename A>
+void Writer<A>::synthesizeStubs()
+{
+       switch ( fOptions.outputKind() ) {
+               case Options::kStaticExecutable:
+               case Options::kDyld:
+               case Options::kObjectFile:
+                       // these output kinds never have stubs
+                       return;
+               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*>::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;
+                       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());
+                               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;
+                                               }
+                                       }
+                               }
+                       }
+                       // create stubs as needed
+                       if ( this->stubableReferenceKind(ref->getKind())
+                               && this->relocationNeededInFinalLinkedImage(target) == kRelocExternal ) {
+                               ObjectFile::Atom* stub = NULL;
+                               std::map<ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fStubsMap.find(&target);
+                               if ( pos == fStubsMap.end() ) {
+                                       stub = new StubAtom<A>(*this, target);
+                                       fStubsMap[&target] = stub;
+                               }
+                               else {
+                                       stub = pos->second;
+                               }
+                               // alter reference to use stub instead
+                               ref->setTarget(*stub, 0);
+                       }
+                       // create GOT slots (non-lazy pointers) as needed
+                       else if ( this->GOTReferenceKind(ref->getKind()) ) {
+                               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, 0);
+                       }
+               }
+       }
+
+       // sort stubs
+
+       // sort lazy pointers
+
+       // add stubs to fAllAtoms
+       if ( fAllSynthesizedStubs.size() != 0 ) {
+               std::vector<ObjectFile::Atom*>* stubs = (std::vector<ObjectFile::Atom*>*)&fAllSynthesizedStubs;
+               std::vector<ObjectFile::Atom*> mergedStubs;
+               if ( fAllSynthesizedStubHelpers.size() != 0 ) {
+                       // when we have stubs and helpers, insert both into fAllAtoms
+                       mergedStubs.insert(mergedStubs.end(), fAllSynthesizedStubs.begin(), fAllSynthesizedStubs.end());
+                       mergedStubs.insert(mergedStubs.end(), fAllSynthesizedStubHelpers.begin(), fAllSynthesizedStubHelpers.end());
+                       stubs = &mergedStubs;
+               }
+               ObjectFile::Section* curSection = NULL;
+               ObjectFile::Atom* prevAtom = NULL;
+               for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
+                       ObjectFile::Atom* atom = *it;
+                       ObjectFile::Section* nextSection = atom->getSection();
+                       if ( nextSection != curSection ) {
+                               // HACK HACK for i386 where stubs are not in _TEXT segment
+                               if ( strcmp(fAllSynthesizedStubs[0]->getSegment().getName(), "__IMPORT") == 0 ) {
+                                       if ( ((prevAtom != NULL) && (strcmp(prevAtom->getSegment().getName(), "__IMPORT") == 0))
+                                               || (strcmp(atom->getSegment().getName(), "__LINKEDIT") == 0) ) {
+                                               // insert stubs at end of __IMPORT segment, or before __LINKEDIT
+                                               fAllAtoms->insert(it, fAllSynthesizedStubs.begin(), fAllSynthesizedStubs.end());
+                                               break;
+                                       }
+                               }
+                               else {
+                                       if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__text") == 0) ) {
+                                               // found end of __text section, insert stubs here
+                                               fAllAtoms->insert(it, stubs->begin(), stubs->end());
+                                               break;
+                                       }
+                               }
+                               curSection = nextSection;
+                       }
+                       prevAtom = atom;
+               }
+       }
+
+
+       // add lazy pointers to fAllAtoms
+       if ( fAllSynthesizedLazyPointers.size() != 0 ) {
+               ObjectFile::Section* curSection = NULL;
+               ObjectFile::Atom* prevAtom = NULL;
+               bool inserted = false;
+               for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
+                       ObjectFile::Atom* atom = *it;
+                       ObjectFile::Section* nextSection = atom->getSection();
+                       if ( nextSection != curSection ) {
+                               if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__dyld") == 0) ) {
+                                       // found end of __dyld section, insert lazy pointers here
+                                       fAllAtoms->insert(it, fAllSynthesizedLazyPointers.begin(), fAllSynthesizedLazyPointers.end());
+                                       inserted = true;
+                                       break;
+                               }
+                               curSection = nextSection;
+                       }
+                       prevAtom = atom;
+               }
+               if ( !inserted ) {
+                       throw "can't insert lazy pointers, __dyld section not found";
+               }
+       }
+       
+       // add non-lazy pointers to fAllAtoms
+       if ( fAllSynthesizedNonLazyPointers.size() != 0 ) {
+               ObjectFile::Section* curSection = NULL;
+               ObjectFile::Atom* prevAtom = NULL;
+               bool inserted = false;
+               for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
+                       ObjectFile::Atom* atom = *it;
+                       ObjectFile::Section* nextSection = atom->getSection();
+                       if ( nextSection != curSection ) {
+                               if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__dyld") == 0) ) {
+                                       // found end of __dyld section, insert lazy pointers here
+                                       fAllAtoms->insert(it, fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end());
+                                       inserted = true;
+                                       break;
+                               }
+                               curSection = nextSection;
+                       }
+                       prevAtom = atom;
+               }
+               if ( !inserted ) {
+                       throw "can't insert non-lazy pointers, __dyld section not found";
+               }
+       }
+}
+
+
+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 = NULL;
+       SectionInfo* currentSectionInfo = NULL;
+       SegmentInfo* currentSegmentInfo = 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) && (strcmp(atom->getSectionName(),currentSectionInfo->fSectionName) != 0)) ) {
+                       if ( oneSegmentCommand ) {
+                               if ( currentSegmentInfo == NULL ) {
+                                       currentSegmentInfo = new SegmentInfo();
+                                       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();
+                               currentSectionInfo->fAllZeroFill = atom->isZeroFill();
+                               currentSectionInfo->fVirtualSection = ( (currentSectionInfo->fSectionName[0] == '.') || (oneSegmentCommand && (atom->getDefinitionKind()==ObjectFile::Atom::kTentativeDefinition)) );
+                               if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
+                                       currentSectionInfo->setIndex(sectionIndex++);
+                               currentSegmentInfo->fSections.push_back(currentSectionInfo);
+                       }
+                       else {
+                               if ( (currentSegmentInfo == NULL) || (strcmp(currentSegmentInfo->fName, atom->getSegment().getName()) != 0) ) {
+                                       currentSegmentInfo = new SegmentInfo();
+                                       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;
+                                       currentSegmentInfo->fInitProtection = initprot;
+                                       if ( initprot == 0 )
+                                               currentSegmentInfo->fMaxProtection = 0;  // pagezero should have maxprot==initprot==0
+                                       else
+                                               currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
+                                       currentSegmentInfo->fBaseAddress = atom->getSegment().getBaseAddress();
+                                       currentSegmentInfo->fFixedAddress = atom->getSegment().hasFixedAddress();
+                                       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();
+                               // 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);
+                       }
+                       if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "._load_commands") == 0) ) {
+                               fLoadCommandsSection = currentSectionInfo;
+                               fLoadCommandsSegment = currentSegmentInfo;
+                       }
+                       if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_symbol_ptr") == 0) )
+                               currentSectionInfo->fAllLazyPointers = true;
+                       if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_sym_ptr2") == 0) )
+                               currentSectionInfo->fAllLazyPointers = true;
+                       if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__nl_symbol_ptr") == 0) )
+                               currentSectionInfo->fAllNonLazyPointers = true;
+                       if ( (strcmp(currentSectionInfo->fSegmentName, "__IMPORT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__pointers") == 0) )
+                               currentSectionInfo->fAllNonLazyPointers = true;
+                       if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub1") == 0) )
+                               currentSectionInfo->fAllStubs = true;
+                       if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub1") == 0) )
+                               currentSectionInfo->fAllStubs = true;
+                       if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__picsymbolstub2") == 0) )
+                               currentSectionInfo->fAllStubs = true;
+                       if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__symbol_stub") == 0) )
+                               currentSectionInfo->fAllStubs = true;
+                       if ( (strcmp(currentSectionInfo->fSegmentName, "__IMPORT") == 0) && (strcmp(currentSectionInfo->fSectionName, "__jump_table") == 0) )
+                               currentSectionInfo->fAllSelfModifyingStubs = true;
+                       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();
+               if ( currentSectionInfo->fAlignment < atomAlign )
+                       currentSectionInfo->fAlignment = atomAlign;
+               // calculate section offset for this atom
+               uint64_t offset = currentSectionInfo->fSize;
+               uint64_t alignment = 1 << atomAlign;
+               offset = ( (offset+alignment-1) & (-alignment) );
+               atom->setSectionOffset(offset);
+               uint64_t curAtomSize = atom->getSize();
+               currentSectionInfo->fSize = offset + curAtomSize;
+               // add atom to section vector
+               currentSectionInfo->fAtoms.push_back(atom);
+               // update largest size
+               if ( !currentSectionInfo->fAllZeroFill && (curAtomSize > fLargestAtomSize) )
+                       fLargestAtomSize = curAtomSize;
+       }
+}
+
+
+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->addPPCBranchIslands();
+}
+
+template <>
+bool Writer<ppc64>::addBranchIslands()
+{
+       return this->addPPCBranchIslands();
+}
+
+template <>
+bool Writer<x86>::addBranchIslands()
+{
+       // x86 branches can reach entire 4G address space, so no need for branch islands
+       return false;
+}
+
+
+template <>
+inline uint8_t Writer<ppc>::branch24Reference()
+{
+       return ppc::kBranch24;
+}
+
+template <>
+inline uint8_t Writer<ppc64>::branch24Reference()
+{
+       return ppc64::kBranch24;
+}
+
+//
+// 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 hoping to the target.
+//
+// Branch Island Algorithm
+//
+// If the __TEXT segment < 16MB, then no branch islands needed
+// Otherwise, every 15MB into the __TEXT segment is 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
+// 15MB which means the region would have to be 1MB (256K islands)
+// before any branches could be pushed out of range.
+//
+template <typename A>
+bool Writer<A>::addPPCBranchIslands()
+{
+       bool result = false;
+       // Can only possibly need branch islands if __TEXT segment > 16M
+       if ( fLoadCommandsSegment->fSize > 16000000 ) {
+               //fprintf(stderr, "ld64: checking for branch islands, __TEXT segment size=%llu\n", fLoadCommandsSegment->fSize);
+               const uint32_t kBetweenRegions = 15000000; // place regions of islands every 15MB 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;
+                               //fprintf(stderr, "ld64: 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;
+
+               // 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 ( ref->getKind() == this->branch24Reference() ) {
+                                       ObjectFile::Atom& target = ref->getTarget();
+                                       int64_t srcAddr = atom->getAddress() + ref->getFixUpOffset();
+                                       int64_t dstAddr = target.getAddress() + ref->getTargetOffset();
+                                       int64_t displacement = dstAddr - srcAddr;
+                                       const int64_t kFifteenMegLimit = kBetweenRegions;
+                                       if ( (displacement > kFifteenMegLimit) || (displacement < (-kFifteenMegLimit)) ) {
+                                               for (int i=0; i < kIslandRegionsCount; ++i) {
+                                                       AtomToIsland* region=&regionsMap[i];
+                                                       int64_t islandRegionAddr = kBetweenRegions * (i+1);
+                                                       if ( ((srcAddr < islandRegionAddr) && (dstAddr > islandRegionAddr))
+                                                          ||((dstAddr < islandRegionAddr) && (srcAddr > islandRegionAddr)) ) {
+                                                               TargetAndOffset islandTarget = { &target, ref->getTargetOffset() };
+                                                               AtomToIsland::iterator pos = region->find(islandTarget);
+                                                               if ( pos == region->end() ) {
+                                                                       BranchIslandAtom<A>* island = new BranchIslandAtom<A>(*this, target.getDisplayName(), i, target, ref->getTargetOffset());
+                                                                       island->setSection(textSection);
+                                                                       (*region)[islandTarget] = island;
+                                                                       regionsIslands[i].push_back(island);
+                                                                       ++islandCount;
+                                                                       ref->setTarget(*island, 0);
+                                                               }
+                                                               else {
+                                                                       ref->setTarget(*(pos->second), 0);
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               // insert islands into __text section and adjust section offsets
+               if ( islandCount > 0 ) {
+                       //fprintf(stderr, "ld64: %u branch islands required\n", islandCount);
+                       std::vector<ObjectFile::Atom*> newAtomList;
+                       newAtomList.reserve(textSection->fAtoms.size()+islandCount);
+                       uint64_t islandRegionAddr = kBetweenRegions;
+                       int regionIndex = 0;
+                       uint64_t sectionOffset = 0;
+                       for (std::vector<ObjectFile::Atom*>::iterator it=textSection->fAtoms.begin(); it != textSection->fAtoms.end(); it++) {
+                               ObjectFile::Atom* atom = *it;
+                               newAtomList.push_back(atom);
+                               if ( atom->getAddress() > islandRegionAddr ) {
+                                       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());
+                                               sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
+                                               islandAtom->setSectionOffset(sectionOffset);
+                                               sectionOffset += islandAtom->getSize();
+                                       }
+                                       ++regionIndex;
+                                       islandRegionAddr += kBetweenRegions;
+                               }
+                               uint64_t alignment = 1 << (atom->getAlignment());
+                               sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
+                               atom->setSectionOffset(sectionOffset);
+                               sectionOffset += atom->getSize();
+                       }
+                       // put any remaining islands at end of __text section
+                       if ( regionIndex < kIslandRegionsCount ) {
+                               sectionOffset = textSection->fSize;
+                               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());
+                                       sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
+                                       islandAtom->setSectionOffset(sectionOffset);
+                                       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();
+               offset = ( (offset+alignment-1) & (-alignment) );
+               atom->setSectionOffset(offset);
+               uint32_t atomSize = atom->getSize();
+               if ( atomSize > fLargestAtomSize )
+                       fLargestAtomSize = atomSize;
+               offset += atomSize;
+               fLoadCommandsSection->fSize = offset;
+       }
+
+       std::vector<SectionInfo*>& sectionInfos = fLoadCommandsSegment->fSections;
+       const int sectionCount = sectionInfos.size();
+       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
+               uint32_t totalSizeOfHeaderAndLoadCommands = 0;
+               for(int j=0; j < sectionCount; ++j) {
+                       SectionInfo* curSection = sectionInfos[j];
+                       totalSizeOfHeaderAndLoadCommands += curSection->fSize;
+                       if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
+                               break;
+               }
+               paddingSize = 4096 - (totalSizeOfHeaderAndLoadCommands % 4096);
+       }
+       else if ( fOptions.outputKind() == Options::kObjectFile ) {
+               // mach-o .o files need no padding between load commands and first section
+               paddingSize = 0;
+       }
+       else {
+               // calculate max padding to keep segment size same, but all free space at end of load commands
+               uint64_t totalSize = 0;
+               uint64_t worstCaseAlignmentPadding = 0;
+               for(int j=0; j < sectionCount; ++j) {
+                       SectionInfo* curSection = sectionInfos[j];
+                       totalSize += curSection->fSize;
+                       if ( j != 0 ) // don't count aligment of mach_header which is page-aligned
+                               worstCaseAlignmentPadding += (1 << curSection->fAlignment) - 1;
+               }
+               uint64_t segmentSize = ((totalSize+worstCaseAlignmentPadding+4095) & (-4096));
+               // don't know exactly how it will layout, but we can inflate padding atom this big and still keep aligment constraints
+               paddingSize = segmentSize - (totalSize+worstCaseAlignmentPadding);
+
+               // if command line requires more padding than this
+               if ( paddingSize < fOptions.minimumHeaderPad() ) {
+                       int extraPages = (fOptions.minimumHeaderPad() - paddingSize + 4095)/4096;
+                       paddingSize += extraPages * 4096;
+               }
+       }
+
+       // 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;
+       }
+}
+
+// assign file offsets and logical address to all segments
+template <typename A>
+void Writer<A>::assignFileOffsets()
+{
+       bool finalLinkedImage = (fOptions.outputKind() != Options::kObjectFile);
+       bool haveFixedSegments = false;
+       uint64_t fileOffset = 0;
+       uint64_t nextContiguousAddress = fOptions.baseAddress();
+
+       // 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;
+               
+               fileOffset = (fileOffset+4095) & (-4096);
+               curSegment->fFileOffset = fileOffset;
+               
+               // Set the segment base address
+               if ( curSegment->fFixedAddress )
+                       haveFixedSegments = true;
+               else
+                       curSegment->fBaseAddress = nextContiguousAddress;
+
+               // 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;
+                       address    = ( (address+alignment-1) & (-alignment) );
+                       
+                       // adjust file offset to match address
+                       if ( prevSection != NULL ) {
+                               fileOffset = (address - prevSection->getBaseAddress()) + prevSection->fFileOffset;
+                       }
+                       
+                       // update section info
+                       curSection->fFileOffset = fileOffset;
+                       curSection->setBaseAddress(address);
+                       
+                       // keep track of trailing zero fill sections
+                       if ( curSection->fAllZeroFill && (firstZeroFillSection == NULL) )
+                               firstZeroFillSection = curSection;
+                       if ( !curSection->fAllZeroFill && (firstZeroFillSection != NULL) && finalLinkedImage ) 
+                               throwf("zero-fill section %s not at end of segment", curSection->fSectionName);
+                       
+                       // update running pointers
+                       address += curSection->fSize;
+                       fileOffset += curSection->fSize;
+                       
+                       // 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 = (curSegment->fFileSize+4095) & (-4096);
+                       curSegment->fSize         = (curSegment->fSize+4095) & (-4096);
+                       if ( curSegment->fBaseAddress == nextContiguousAddress )
+                               nextContiguousAddress = (curSegment->fBaseAddress+curSegment->fSize+4095) & (-4096);
+               }
+       }
+
+       // 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 {
+                                                       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);
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+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 sectionCount = lastSeg->fSections.size();
+       uint64_t fileOffset = lastSeg->fSections[firstLinkEditSectionIndex]->fFileOffset;
+       uint64_t address = lastSeg->fSections[firstLinkEditSectionIndex]->getBaseAddress();
+       for (unsigned int i=firstLinkEditSectionIndex; i < sectionCount; ++i) {
+               std::vector<class ObjectFile::Atom*>& atoms = lastSeg->fSections[i]->fAtoms;
+               const unsigned int atomCount = atoms.size();
+               uint64_t sectionOffset = 0;
+               lastSeg->fSections[i]->fFileOffset = fileOffset;
+               lastSeg->fSections[i]->setBaseAddress(address);
+               for (unsigned int j=0; j < atomCount; ++j) {
+                       ObjectFile::Atom* atom = atoms[j];
+                       uint64_t alignment = 1 << atom->getAlignment();
+                       sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
+                       atom->setSectionOffset(sectionOffset);
+                       uint64_t size = atom->getSize();
+                       sectionOffset += size;
+                       if ( size > fLargestAtomSize )
+                               fLargestAtomSize = size;
+               }
+               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:
+                       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:
+               case Options::kStaticExecutable:
+                       return ObjectFile::Atom::kSymbolTableInAndNeverStrip;
+               case Options::kDynamicLibrary:
+               case Options::kDynamicBundle:
+               case Options::kDyld:
+                       return ObjectFile::Atom::kSymbolTableIn;
+               case Options::kObjectFile:
+                       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:
+                       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:
+                       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;
+       }
+
+       // get flags
+       uint32_t flags = 0;
+       if ( fWriter.fOptions.outputKind() == Options::kObjectFile ) {
+               if ( ! fWriter.fSeenFollowOnReferences )
+                       flags = MH_SUBSECTIONS_VIA_SYMBOLS;
+       }
+       else {
+               if ( fWriter.fOptions.outputKind() == Options::kStaticExecutable ) {
+                       flags |= MH_NOUNDEFS;
+               }
+               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;
+                       }
+                       if ( fWriter.fHasWeakExports )
+                               flags |= MH_WEAK_DEFINES;
+                       if ( fWriter.fReferencesWeakImports || fWriter.fHasWeakExports )
+                               flags |= MH_BINDS_TO_WEAK;
+               }
+               if ( fWriter.fOptions.hasExecutableStack() )
+                       flags |= MH_ALLOW_STACK_EXECUTION;
+       }
+
+       // get commands info
+       uint32_t commandsSize = 0;
+       uint32_t commandsCount = 0;
+
+       std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fWriter.fLoadCommandsSection->fAtoms;
+       const unsigned int atomCount = loadCommandAtoms.size();
+       for (unsigned int i=0; i < atomCount; ++i) {
+               ObjectFile::Atom* atom = loadCommandAtoms[i];
+               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(CPU_SUBTYPE_POWERPC_ALL);
+}
+
+template <>
+void MachHeaderAtom<ppc64>::setHeaderInfo(macho_header<ppc64::P>& header) const
+{
+       header.set_magic(MH_MAGIC_64);
+       header.set_cputype(CPU_TYPE_POWERPC64);
+       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 <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 <typename A>
+void SegmentLoadCommandsAtom<A>::computeSize()
+{
+       uint64_t size = 0;
+       std::vector<SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
+       const int segCount = segmentInfos.size();
+       for(int i=0; i < segCount; ++i) {
+               size += sizeof(macho_segment_command<P>);
+               std::vector<SectionInfo*>& sectionInfos = segmentInfos[i]->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;
+}
+
+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 <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;
+       const int segCount = segmentInfos.size();
+       for(int i=0; i < segCount; ++i) {
+               SegmentInfo* segInfo = segmentInfos[i];
+               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(segInfo->fSize);
+               cmd->set_fileoff(segInfo->fFileOffset);
+               cmd->set_filesize(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);
+                                       }
+                                       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->fAllNonLazyPointers ) {
+                                       sect->set_flags(S_NON_LAZY_SYMBOL_POINTERS);
+                                       sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
+                               }
+                               else if ( sectInfo->fAllStubs ) {
+                                       sect->set_flags(S_SYMBOL_STUBS);
+                                       sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
+                                       sect->set_reserved2(sectInfo->fSize / sectInfo->fAtoms.size());
+                               }
+                               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 ( (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, "__eh_frame") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
+                                       sect->set_flags(S_COALESCED);
+                               }
+                               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, "__cstring") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
+                                       sect->set_flags(S_CSTRING_LITERALS);
+                               }
+                               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, "__message_refs") == 0) && (strcmp(sectInfo->fSegmentName, "__OBJC") == 0) ) {
+                                       sect->set_flags(S_LITERAL_POINTERS);
+                               }
+                       }
+               }
+               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, Segment::fgTextSegment)
+{
+       bzero(&fSymbolTable, sizeof(macho_symtab_command<P>));
+       bzero(&fDynamicSymbolTable, sizeof(macho_dysymtab_command<P>));
+       writer.fSymbolTableCommands = this;
+}
+
+template <typename A>
+uint64_t SymbolTableLoadCommandsAtom<A>::getSize() const
+{
+       if ( fWriter.fOptions.outputKind() == Options::kStaticExecutable )
+               return this->alignedSize(sizeof(macho_symtab_command<P>));
+       else
+               return this->alignedSize(sizeof(macho_symtab_command<P>) + sizeof(macho_dysymtab_command<P>));
+}
+
+template <typename A>
+void SymbolTableLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+       // build LC_DYSYMTAB 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.fSymbolTableAtom->getFileOffset());
+       symbolTableCmd->set_stroff(fWriter.fStringsAtom->getFileOffset());
+       symbolTableCmd->set_strsize(fWriter.fStringsAtom->getSize());
+
+       // build LC_DYSYMTAB command
+       if ( fWriter.fOptions.outputKind() != Options::kStaticExecutable ) {
+               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);
+               dynamicSymbolTableCmd->set_indirectsymoff(fWriter.fIndirectTableAtom->getFileOffset());
+               dynamicSymbolTableCmd->set_nindirectsyms(fWriter.fIndirectTableAtom->fTable.size());
+               if ( fWriter.fOptions.outputKind() != Options::kObjectFile ) {
+                       dynamicSymbolTableCmd->set_extreloff((fWriter.fExternalRelocs.size()==0) ? 0 : fWriter.fExternalRelocationsAtom->getFileOffset());
+                       dynamicSymbolTableCmd->set_nextrel(fWriter.fExternalRelocs.size());
+                       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 (fWriter.fOptions.outputKind() == Options::kStaticExecutable) ? 1 : 2;
+}
+
+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
+{
+       const char* path = fInfo.reader->getInstallPath();
+       if ( fInfo.options.fInstallPathOverride != NULL )
+               path = fInfo.options.fInstallPathOverride;
+       return this->alignedSize(sizeof(macho_dylib_command<P>) + strlen(path) + 1);
+}
+
+template <typename A>
+void DylibLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+       uint64_t size = this->getSize();
+       bzero(buffer, size);
+       const char* path = fInfo.reader->getInstallPath();
+       if ( fInfo.options.fInstallPathOverride != NULL )
+               path = fInfo.options.fInstallPathOverride;
+       macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)buffer;
+       if ( fInfo.options.fWeakImport )
+               cmd->set_cmd(LC_LOAD_WEAK_DYLIB);
+       else
+               cmd->set_cmd(LC_LOAD_DYLIB);
+       cmd->set_cmdsize(this->getSize());
+       cmd->set_timestamp(fInfo.reader->getTimestamp());
+       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
+{
+       struct timeval currentTime = { 0 , 0 };
+       gettimeofday(&currentTime, NULL);
+       time_t timestamp = currentTime.tv_sec;
+       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(timestamp);
+       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);
+       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>::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 <>
+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(6, 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(15, fWriter.fOptions.customStackAddr());       // uesp
+}
+
+
+
+
+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>
+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
+{
+       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>
+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
+{
+       return kBufferSize * fFullBuffers.size() + fCurrentBufferUsed;
+}
+
+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);
+}
+
+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>
+BranchIslandAtom<A>::BranchIslandAtom(Writer<A>& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset)
+ : WriterAtom<A>(writer, Segment::fgTextSegment), fTarget(target), fTargetOffset(targetOffset)
+{
+       char* buf = new char[strlen(name)+32];
+       if ( targetOffset == 0 ) {
+               if ( islandRegion == 0 )
+                       sprintf(buf, "%s$island", name);
+               else
+                       sprintf(buf, "%s$island_%d", name, islandRegion);
+       }
+       else {
+               sprintf(buf, "%s_plus_%d$island_%d", name, targetOffset, islandRegion);
+       }
+       fName = buf;
+}
+
+
+template <>
+void BranchIslandAtom<ppc>::copyRawContent(uint8_t buffer[]) const
+{
+       int64_t displacement = fTarget.getAddress() + fTargetOffset - 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 = fTarget.getAddress() + fTargetOffset - this->getAddress();
+       int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
+       OSWriteBigInt32(buffer, 0, branchInstruction);
+}
+
+template <>
+uint64_t BranchIslandAtom<ppc>::getSize() const
+{
+       return 4;
+}
+
+template <>
+uint64_t BranchIslandAtom<ppc64>::getSize() const
+{
+       return 4;
+}
+
+
+template <>
+bool StubAtom<ppc64>::pic() const
+{
+       // no-pic stubs for ppc64 don't work if lazy pointer is above low 2GB.
+       // This usually only happens when a large zero-page is requested
+       switch ( fWriter.fOptions.outputKind() ) {
+               case Options::kDynamicExecutable:
+                       return (fWriter.fOptions.zeroPageSize() > 4096);
+               case Options::kDynamicLibrary:
+               case Options::kDynamicBundle:
+                       return true;
+               case Options::kObjectFile:
+               case Options::kDyld:
+               case Options::kStaticExecutable:
+                       break;
+       }
+       throw "internal ld64 error: file type does not use stubs";
+}
+
+template <>
+bool StubAtom<ppc>::pic() const
+{
+       return ( fWriter.fOptions.outputKind() != Options::kDynamicExecutable );
+}
+
+
+template <>
+StubAtom<ppc>::StubAtom(Writer<ppc>& writer, ObjectFile::Atom& target)
+ : WriterAtom<ppc>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
+{
+       writer.fAllSynthesizedStubs.push_back(this);
+
+       LazyPointerAtom<ppc>* lp = new LazyPointerAtom<ppc>(writer, target);
+       if ( pic() ) {
+               // picbase is 8 bytes into atom
+               fReferences.push_back(new WriterReference<ppc>(12, ppc::kPICBaseHigh16, lp, 0, NULL, 8));
+               fReferences.push_back(new WriterReference<ppc>(20, ppc::kPICBaseLow16, lp, 0, NULL, 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)
+ : WriterAtom<ppc64>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
+{
+       writer.fAllSynthesizedStubs.push_back(this);
+
+       LazyPointerAtom<ppc64>* lp = new LazyPointerAtom<ppc64>(writer, target);
+       if ( pic() ) {
+               // picbase is 8 bytes into atom
+               fReferences.push_back(new WriterReference<ppc64>(12, ppc64::kPICBaseHigh16, lp, 0, NULL, 8));
+               fReferences.push_back(new WriterReference<ppc64>(20, ppc64::kPICBaseLow14, lp, 0, NULL, 8));
+       }
+       else {
+               fReferences.push_back(new WriterReference<ppc64>(0, ppc64::kAbsHigh16AddLow, lp));
+               fReferences.push_back(new WriterReference<ppc64>(4, ppc64::kAbsLow14, lp));
+       }
+}
+
+// specialize to put x86 fast stub in __IMPORT segment with no lazy pointer
+template <>
+StubAtom<x86>::StubAtom(Writer<x86>& writer, ObjectFile::Atom& target)
+ : WriterAtom<x86>(writer, Segment::fgImportSegment), fName(stubName(target.getName())), fTarget(target)
+{
+       writer.fAllSynthesizedStubs.push_back(this);
+}
+
+
+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 ( pic() ? 32 : 16 );
+}
+
+template <>
+uint64_t StubAtom<ppc64>::getSize() const
+{
+       return ( pic() ? 32 : 16 );
+}
+
+template <>
+uint64_t StubAtom<x86>::getSize() const
+{
+       return 5;
+}
+
+
+template <>
+uint8_t StubAtom<x86>::getAlignment() const
+{
+       // special case x86 fast stubs to be byte aligned
+       return 0;
+}
+
+template <>
+void StubAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
+{
+       if ( pic() ) {
+               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 ( pic() ) {
+               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
+{
+       buffer[0] = 0xF4;
+       buffer[1] = 0xF4;
+       buffer[2] = 0xF4;
+       buffer[3] = 0xF4;
+       buffer[4] = 0xF4;
+}
+
+
+template <>
+const char*    StubAtom<ppc>::getSectionName() const
+{
+       return ( pic() ? "__picsymbolstub1" : "__symbol_stub1");
+}
+
+template <>
+const char*    StubAtom<ppc64>::getSectionName() const
+{
+       return ( pic() ? "__picsymbolstub1" : "__symbol_stub1");
+}
+
+template <>
+const char*    StubAtom<x86>::getSectionName() const
+{
+       return "__jump_table";
+}
+
+
+
+
+
+template <typename A>
+LazyPointerAtom<A>::LazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target)
+ : WriterAtom<A>(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target)
+{
+       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>
+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());
+}
+
+
+
+}; // namespace executable
+}; // namespace mach_o
+
+
+#endif // __EXECUTABLE_MACH_O__
diff --git a/src/ObjDump.cpp b/src/ObjDump.cpp
deleted file mode 100644 (file)
index e3d6082..0000000
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
- */
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <fcntl.h>
-#include <fcntl.h>
-#include <mach-o/loader.h>
-#include <mach-o/fat.h>
-#include <mach-o/stab.h>
-
-
-#include "ObjectFile.h"
-#include "ObjectFileMachO-all.h"
-
- __attribute__((noreturn))
-void throwf(const char* format, ...) 
-{
-       va_list list;
-       char*   p;
-       va_start(list, format);
-       vasprintf(&p, format, list);
-       va_end(list);
-       
-       const char*     t = p;
-       throw t;
-}
-
-static void dumpStabs(std::vector<ObjectFile::StabsInfo>* stabs)
-{
-       // debug info
-       const int stabCount = stabs->size();
-       printf("stabs: (%u)\n", stabCount);
-       for (int i=0; i < stabCount; ++i) {
-               ObjectFile::StabsInfo& stab = (*stabs)[i];
-               const char* code = "?????";
-               switch (stab.type) {
-                       case N_GSYM:
-                               code = " GSYM";
-                               break;
-                       case N_FNAME:
-                               code = "FNAME";
-                               break;
-                       case N_FUN:
-                               code = "  FUN";
-                               break;
-                       case N_STSYM:
-                               code = "STSYM";
-                               break;
-                       case N_LCSYM:
-                               code = "LCSYM";
-                               break;
-                       case N_BNSYM:
-                               code = "BNSYM";
-                               break;
-                       case N_OPT:
-                               code = "  OPT";
-                               break;
-                       case N_RSYM:
-                               code = " RSYM";
-                               break;
-                       case N_SLINE:
-                               code = "SLINE";
-                               break;
-                       case N_ENSYM:
-                               code = "ENSYM";
-                               break;
-                       case N_SSYM:
-                               code = " SSYM";
-                               break;
-                       case N_SO:
-                               code = "   SO";
-                               break;
-                       case N_LSYM:
-                               code = " LSYM";
-                               break;
-                       case N_BINCL:
-                               code = "BINCL";
-                               break;
-                       case N_SOL:
-                               code = "  SOL";
-                               break;
-                       case N_PARAMS:
-                               code = "PARMS";
-                               break;
-                       case N_VERSION:
-                               code = " VERS";
-                               break;
-                       case N_OLEVEL:
-                               code = "OLEVL";
-                               break;
-                       case N_PSYM:
-                               code = " PSYM";
-                               break;
-                       case N_EINCL:
-                               code = "EINCL";
-                               break;
-                       case N_ENTRY:
-                               code = "ENTRY";
-                               break;
-                       case N_LBRAC:
-                               code = "LBRAC";
-                               break;
-                       case N_EXCL:
-                               code = " EXCL";
-                               break;
-                       case N_RBRAC:
-                               code = "RBRAC";
-                               break;
-                       case N_BCOMM:
-                               code = "BCOMM";
-                               break;
-                       case N_ECOMM:
-                               code = "ECOMM";
-                               break;
-                       case N_LENG:
-                               code =  "LENG";
-                               break;
-               }
-               printf("   %08X %02X %04X %s %s\n", (uint32_t)stab.atomOffset, stab.other, stab.desc, code, stab.string);
-       }
-}
-
-
-static void dumpAtom(ObjectFile::Atom* atom)
-{
-       //printf("atom:    %p\n", atom);
-       
-       // name
-       printf("name:    %s\n",  atom->getDisplayName());
-       
-       // scope
-       switch ( atom->getScope() ) {
-               case ObjectFile::Atom::scopeTranslationUnit:
-                       printf("scope:   translation unit\n");
-                       break;
-               case ObjectFile::Atom::scopeLinkageUnit:
-                       printf("scope:   linkage unit\n");
-                       break;
-               case ObjectFile::Atom::scopeGlobal:
-                       printf("scope:   global\n");
-                       break;
-               default:
-                       printf("scope:   unknown\n");
-       }
-       
-       // segment and section
-       printf("section: %s,%s\n", atom->getSegment().getName(), atom->getSectionName());
-
-       // attributes
-       printf("attrs:   ");
-       if ( atom->isWeakDefinition() )
-               printf("weak ");
-       if ( atom->isCoalesableByName() )
-               printf("coalesce-by-name ");
-       if ( atom->isCoalesableByValue() )
-               printf("coalesce-by-value ");
-       if ( atom->dontDeadStrip() )
-               printf("dont-dead-strip ");
-       if ( atom->isZeroFill() )
-               printf("zero-fill ");
-       printf("\n");
-       
-       // size
-       printf("size:    0x%012llX\n", atom->getSize());
-       
-       // alignment
-       printf("align:    %d\n", atom->getAlignment());
-
-       // content
-       uint64_t size = atom->getSize();
-       if ( size < 4096 ) {
-               uint8_t content[size];
-               atom->copyRawContent(content);
-               printf("content: ");
-               if ( strcmp(atom->getSectionName(), "__cstring") == 0 ) {
-                       printf("\"%s\"", content);
-               }
-               else {
-                       for (unsigned int i=0; i < size; ++i)
-                               printf("%02X ", content[i]);
-               }
-       }
-       printf("\n");
-       
-       // references
-       std::vector<ObjectFile::Reference*>&  references = atom->getReferences();
-       const int refCount = references.size();
-       printf("references: (%u)\n", refCount);
-       for (int i=0; i < refCount; ++i) {
-               ObjectFile::Reference* ref = references[i];
-               printf("   %s\n", ref->getDescription());
-       }
-       
-       // debug info
-       std::vector<ObjectFile::StabsInfo>* stabs = atom->getStabsDebugInfo();
-       if ( stabs != NULL )
-               dumpStabs(stabs);
-}
-
-
-static void dumpFile(ObjectFile::Reader* reader)
-{
-#if 0
-       // debug info
-       std::vector<ObjectFile::StabsInfo>* stabs = reader->getStabsDebugInfo();
-       if ( stabs != NULL )
-               dumpStabs(stabs);
-#endif
-       // atom content
-       std::vector<ObjectFile::Atom*> atoms = reader->getAtoms();
-       const int atomCount = atoms.size();
-       for(int i=0; i < atomCount; ++i) {
-               dumpAtom(atoms[i]);
-               printf("\n");
-       }
-}
-
-
-static ObjectFile::Reader* createReader(const char* path, const ObjectFile::ReaderOptions& options)
-{
-       struct stat stat_buf;
-       
-       int fd = ::open(path, O_RDONLY, 0);
-       if ( fd == -1 )
-               throw "cannot open file";
-       ::fstat(fd, &stat_buf);
-       char* p = (char*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE, fd, 0);
-       ::close(fd);
-       const mach_header* mh = (mach_header*)p;
-       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));
-               for (unsigned long i=0; i < fh->nfat_arch; ++i) {
-                       if ( archs[i].cputype == CPU_TYPE_POWERPC64 ) {
-                               p = p + archs[i].offset;
-                               mh = (struct mach_header*)p;
-                       }
-               }
-       }
-       if ( mh->magic == MH_MAGIC ) {
-               if ( mh->filetype == MH_OBJECT ) {
-                       switch ( mh->cputype ) {
-                               case CPU_TYPE_I386:
-                                       return i386::ObjectFileMachO::MakeReader((class i386::macho_header*)mh, path, options);
-                               case CPU_TYPE_POWERPC:
-                                       return ppc::ObjectFileMachO::MakeReader((class ppc::macho_header*)mh, path, options);
-                               case CPU_TYPE_POWERPC64:
-                                       return ppc64::ObjectFileMachO::MakeReader((class ppc64::macho_header*)mh, path, options);
-                               default:
-                                       throw "unknown mach-o cpu type";
-                       }
-               }
-               if ( mh->filetype == MH_DYLIB )
-                       return ppc::ObjectFileDylibMachO::MakeReader((class ppc::macho_header*)mh, path, options);
-               throw "unknown mach-o file type";
-       }
-       else if ( mh->magic == MH_MAGIC_64 ) {
-               if ( mh->filetype == MH_OBJECT )
-                       return ppc64::ObjectFileMachO::MakeReader((class ppc64::macho_header*)mh, path, options);
-               if ( mh->filetype == MH_DYLIB )
-                       return ppc64::ObjectFileDylibMachO::MakeReader((class ppc64::macho_header*)mh, path, options);
-               throw "unknown mach-o file type";
-       }
-       else if ( mh->magic == OSSwapInt32(MH_MAGIC) ) {
-               if ( mh->filetype == OSSwapInt32(MH_OBJECT) ) {
-                       switch ( OSSwapInt32(mh->cputype) ) {
-                               case CPU_TYPE_I386:
-                                       return i386::ObjectFileMachO::MakeReader((class i386::macho_header*)mh, path, options);
-                               case CPU_TYPE_POWERPC:
-                                       return ppc::ObjectFileMachO::MakeReader((class ppc::macho_header*)mh, path, options);
-                               case CPU_TYPE_POWERPC64:
-                                       return ppc64::ObjectFileMachO::MakeReader((class ppc64::macho_header*)mh, path, options);
-                               default:
-                                       throw "unknown mach-o cpu type";
-                       }
-               }
-               if ( mh->filetype == OSSwapInt32(MH_DYLIB) )
-                       return ppc::ObjectFileDylibMachO::MakeReader((class ppc::macho_header*)mh, path, options);
-               throw "unknown mach-o file type";
-       }
-       else if ( mh->magic == OSSwapInt32(MH_MAGIC_64) ) {
-               if ( mh->filetype == OSSwapInt32(MH_OBJECT)  )
-                       return ppc64::ObjectFileMachO::MakeReader((class ppc64::macho_header*)mh, path, options);
-               if ( mh->filetype == OSSwapInt32(MH_DYLIB) )
-                       return ppc64::ObjectFileDylibMachO::MakeReader((class ppc64::macho_header*)mh, path, options);
-               throw "unknown mach-o file type";
-       }
-       throw "unknown file type";
-}
-
-
-int main(int argc, const char* argv[])
-{
-       ObjectFile::ReaderOptions options;
-       //const char* path = argv[1];
-       //ObjectFile::Reader* reader = ObjectFile::Reader::createReader(path);
-       try {
-               ObjectFile::Reader* reader = createReader("/tmp/gcov-1.o", options);
-
-               dumpFile(reader);
-       }
-       catch (const char* msg) {
-               fprintf(stderr, "ObjDump failed: %s\n", msg);
-       }
-       
-       return 0;
-}
-
-
-
diff --git a/src/ObjectDump.cpp b/src/ObjectDump.cpp
new file mode 100644 (file)
index 0000000..7c51e0a
--- /dev/null
@@ -0,0 +1,361 @@
+/* -*- 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@
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <fcntl.h>
+#include <mach-o/loader.h>
+#include <mach-o/fat.h>
+#include <mach-o/stab.h>
+
+#include "MachOReaderRelocatable.hpp"
+
+static bool                    sDumpContent= true;
+static bool                    sDumpStabs      = false;
+static bool                    sSort           = true;
+static cpu_type_t      sPreferredArch = CPU_TYPE_POWERPC64;
+
+
+ __attribute__((noreturn))
+void throwf(const char* format, ...) 
+{
+       va_list list;
+       char*   p;
+       va_start(list, format);
+       vasprintf(&p, format, list);
+       va_end(list);
+       
+       const char*     t = p;
+       throw t;
+}
+
+static void dumpStabs(std::vector<ObjectFile::Reader::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;
+               const char* code = "?????";
+               switch (stab.type) {
+                       case N_GSYM:
+                               code = " GSYM";
+                               break;
+                       case N_FNAME:
+                               code = "FNAME";
+                               break;
+                       case N_FUN:
+                               code = "  FUN";
+                               break;
+                       case N_STSYM:
+                               code = "STSYM";
+                               break;
+                       case N_LCSYM:
+                               code = "LCSYM";
+                               break;
+                       case N_BNSYM:
+                               code = "BNSYM";
+                               break;
+                       case N_OPT:
+                               code = "  OPT";
+                               break;
+                       case N_RSYM:
+                               code = " RSYM";
+                               break;
+                       case N_SLINE:
+                               code = "SLINE";
+                               break;
+                       case N_ENSYM:
+                               code = "ENSYM";
+                               break;
+                       case N_SSYM:
+                               code = " SSYM";
+                               break;
+                       case N_SO:
+                               code = "   SO";
+                               break;
+                       case N_OSO:
+                               code = "  OSO";
+                               break;
+                       case N_LSYM:
+                               code = " LSYM";
+                               break;
+                       case N_BINCL:
+                               code = "BINCL";
+                               break;
+                       case N_SOL:
+                               code = "  SOL";
+                               break;
+                       case N_PARAMS:
+                               code = "PARMS";
+                               break;
+                       case N_VERSION:
+                               code = " VERS";
+                               break;
+                       case N_OLEVEL:
+                               code = "OLEVL";
+                               break;
+                       case N_PSYM:
+                               code = " PSYM";
+                               break;
+                       case N_EINCL:
+                               code = "EINCL";
+                               break;
+                       case N_ENTRY:
+                               code = "ENTRY";
+                               break;
+                       case N_LBRAC:
+                               code = "LBRAC";
+                               break;
+                       case N_EXCL:
+                               code = " EXCL";
+                               break;
+                       case N_RBRAC:
+                               code = "RBRAC";
+                               break;
+                       case N_BCOMM:
+                               code = "BCOMM";
+                               break;
+                       case N_ECOMM:
+                               code = "ECOMM";
+                               break;
+                       case N_LENG:
+                               code =  "LENG";
+                               break;
+               }
+               printf("  [atom=%20s] %02X %04X %s %s\n", ((stab.atom != NULL) ? stab.atom->getDisplayName() : ""), stab.other, stab.desc, code, stab.string);
+       }
+}
+
+
+static void dumpAtom(ObjectFile::Atom* atom)
+{
+       //printf("atom:    %p\n", atom);
+       
+       // name
+       printf("name:    %s\n",  atom->getDisplayName());
+       
+       // scope
+       switch ( atom->getScope() ) {
+               case ObjectFile::Atom::scopeTranslationUnit:
+                       printf("scope:   translation unit\n");
+                       break;
+               case ObjectFile::Atom::scopeLinkageUnit:
+                       printf("scope:   linkage unit\n");
+                       break;
+               case ObjectFile::Atom::scopeGlobal:
+                       printf("scope:   global\n");
+                       break;
+               default:
+                       printf("scope:   unknown\n");
+       }
+       
+       // kind
+       switch ( atom->getDefinitionKind() ) {
+               case ObjectFile::Atom::kRegularDefinition:
+                       printf("kind:     regular\n");
+                       break;
+               case ObjectFile::Atom::kWeakDefinition:
+                       printf("kind:     weak\n");
+                       break;
+               case ObjectFile::Atom::kTentativeDefinition:
+                       printf("kind:     tentative\n");
+                       break;
+               case ObjectFile::Atom::kExternalDefinition:
+                       printf("kind:     import\n");
+                       break;
+               case ObjectFile::Atom::kExternalWeakDefinition:
+                       printf("kind:     weak import\n");
+                       break;
+               default:
+                       printf("scope:   unknown\n");
+       }
+
+       // segment and section
+       printf("section: %s,%s\n", atom->getSegment().getName(), atom->getSectionName());
+
+       // attributes
+       printf("attrs:   ");
+       if ( atom->dontDeadStrip() )
+               printf("dont-dead-strip ");
+       if ( atom->isZeroFill() )
+               printf("zero-fill ");
+       printf("\n");
+       
+       // size
+       printf("size:    0x%012llX\n", atom->getSize());
+       
+       // alignment
+       printf("align:    %d\n", atom->getAlignment());
+
+       // content
+       if ( sDumpContent ) { 
+               uint64_t size = atom->getSize();
+               if ( size < 4096 ) {
+                       uint8_t content[size];
+                       atom->copyRawContent(content);
+                       printf("content: ");
+                       if ( strcmp(atom->getSectionName(), "__cstring") == 0 ) {
+                               printf("\"%s\"", content);
+                       }
+                       else {
+                               for (unsigned int i=0; i < size; ++i)
+                                       printf("%02X ", content[i]);
+                       }
+               }
+               printf("\n");
+       }
+       
+       // references
+       std::vector<ObjectFile::Reference*>&  references = atom->getReferences();
+       const int refCount = references.size();
+       printf("references: (%u)\n", refCount);
+       for (int i=0; i < refCount; ++i) {
+               ObjectFile::Reference* ref = references[i];
+               printf("   %s\n", ref->getDescription());
+       }
+       
+       // line info
+       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) {
+                       printf("   offset 0x%04X, line %d, file %s\n", it->atomOffset, it->lineNumber, it->fileName);
+               }
+       }
+
+}
+
+struct AtomSorter
+{
+     bool operator()(ObjectFile::Atom* left, ObjectFile::Atom* right)
+     {
+          return (strcmp(left->getDisplayName(), right->getDisplayName()) < 0);
+     }
+};
+
+
+static void dumpFile(ObjectFile::Reader* reader)
+{
+       // stabs debug info
+       if ( sDumpStabs && (reader->getDebugInfoKind() == ObjectFile::Reader::kDebugInfoStabs) ) {
+               std::vector<ObjectFile::Reader::Stab>* stabs = reader->getStabs();
+               if ( stabs != NULL )
+                       dumpStabs(stabs);
+       }
+       
+       // get all atoms
+       std::vector<ObjectFile::Atom*> atoms = reader->getAtoms();
+       
+       // make copy of vector and sort (so output is canonical)
+       std::vector<ObjectFile::Atom*> sortedAtoms(atoms);
+       if ( sSort )
+               std::sort(sortedAtoms.begin(), sortedAtoms.end(), AtomSorter());
+       
+       for(std::vector<ObjectFile::Atom*>::iterator it=sortedAtoms.begin(); it != sortedAtoms.end(); ++it) {
+               dumpAtom(*it);
+               printf("\n");
+       }
+}
+
+
+static ObjectFile::Reader* createReader(const char* path, const ObjectFile::ReaderOptions& options)
+{
+       struct stat stat_buf;
+       
+       int fd = ::open(path, O_RDONLY, 0);
+       if ( fd == -1 )
+               throwf("cannot open file: %s", path);
+       ::fstat(fd, &stat_buf);
+       uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE, fd, 0);
+       ::close(fd);
+       const mach_header* mh = (mach_header*)p;
+       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));
+               for (unsigned long i=0; i < fh->nfat_arch; ++i) {
+                       if ( archs[i].cputype == sPreferredArch ) {
+                               p = p + archs[i].offset;
+                               mh = (struct mach_header*)p;
+                       }
+               }
+       }
+       if ( mach_o::relocatable::Reader<x86>::validFile(p) )
+               return mach_o::relocatable::Reader<x86>::make(p, path, 0, options);
+       else if ( mach_o::relocatable::Reader<ppc>::validFile(p) )
+               return mach_o::relocatable::Reader<ppc>::make(p, path, 0, options);
+       else if ( mach_o::relocatable::Reader<ppc64>::validFile(p) )
+               return mach_o::relocatable::Reader<ppc64>::make(p, path, 0, options);
+       throwf("not a mach-o object file: %s", path);
+}
+
+
+int main(int argc, const char* argv[])
+{
+       ObjectFile::ReaderOptions options;
+       try {
+               for(int i=1; i < argc; ++i) {
+                       const char* arg = argv[i];
+                       if ( arg[0] == '-' ) {
+                               if ( strcmp(arg, "-no_content") == 0 ) {
+                                       sDumpContent = false;
+                               }
+                               else if ( strcmp(arg, "-stabs") == 0 ) {
+                                       sDumpStabs = true;
+                               }
+                               else if ( strcmp(arg, "-no_sort") == 0 ) {
+                                       sSort = false;
+                               }
+                               else if ( strcmp(arg, "-arch") == 0 ) {
+                                       const char* arch = argv[++i];
+                                       if ( strcmp(arch, "ppc64") == 0 )
+                                               sPreferredArch = CPU_TYPE_POWERPC64;
+                                       else if ( strcmp(arch, "ppc") == 0 )
+                                               sPreferredArch = CPU_TYPE_POWERPC;
+                                       else if ( strcmp(arch, "i386") == 0 )
+                                               sPreferredArch = CPU_TYPE_I386;
+                                       else 
+                                               throwf("unknown architecture %s", arch);
+                               }
+                               else {
+                                       throwf("unknown option: %s\n", arg);
+                               }
+                       }
+                       else {
+                               ObjectFile::Reader* reader = createReader(arg, options);
+                               dumpFile(reader);
+                       }
+               }
+       }
+       catch (const char* msg) {
+               fprintf(stderr, "ObjDump failed: %s\n", msg);
+               return 1;
+       }
+       
+       return 0;
+}
+
+
+
index 255c028a7738005d52161056c79214a90655826f..0be49104af67e3db486456fa3157e1e48123d87c 100644 (file)
@@ -1,16 +1,16 @@
-/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * 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,
@@ -18,7 +18,7 @@
  * 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@
  */
 
 
 
 
+//
+// 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 StabsInfo
+
+struct LineInfo
 {
-       uint64_t        atomOffset;
-       const char* string;
-       uint8_t         type;
-       uint8_t         other;
-       uint16_t        desc;
+       uint32_t        atomOffset;
+       const char* fileName;
+       uint32_t        lineNumber;
 };
 
+
 class ReaderOptions
 {
 public:
-                                               ReaderOptions() : fFullyLoadArchives(false), fLoadObjcClassesInArchives(false), fFlatNamespace(false), 
-                                                                                       fStripDebugInfo(false), fTraceDylibs(false), fTraceIndirectDylibs(false), fTraceArchives(false) {}
+                                               ReaderOptions() : fFullyLoadArchives(false), fLoadObjcClassesInArchives(false), fFlatNamespace(false),
+                                                                                 fDebugInfoStripping(kDebugInfoFull), fTraceDylibs(false), fTraceIndirectDylibs(false), fTraceArchives(false), fTraceOutputFile(NULL) {}
+       enum DebugInfoStripping { kDebugInfoNone, kDebugInfoMinimal, kDebugInfoFull };
 
        bool                            fFullyLoadArchives;
        bool                            fLoadObjcClassesInArchives;
        bool                            fFlatNamespace;
-       bool                            fStripDebugInfo;
+       DebugInfoStripping      fDebugInfoStripping;
        bool                            fTraceDylibs;
        bool                            fTraceIndirectDylibs;
        bool                            fTraceArchives;
+       const char*                     fTraceOutputFile;
 };
 
 
 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;
+       };
+
        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<StabsInfo>*         getStabsDebugInfo() = 0;
-       
+       virtual std::vector<Stab>*                      getStabs() = 0;
+                       unsigned int                            getSortOrder() const { return fSortOrder; }
+                       void                                            setSortOrder(unsigned int order) { fSortOrder=order; }
+
        // For Dynamic Libraries only
        virtual const char*                                     getInstallPath()                        { return NULL; }
        virtual uint32_t                                        getTimestamp()                          { return 0; }
@@ -76,13 +106,14 @@ public:
        virtual uint32_t                                        getCompatibilityVersion()       { return 0; }
        virtual std::vector<const char*>*       getDependentLibraryPaths()      { return NULL; }
        virtual bool                                            reExports(Reader*)                      { return false; }
-       virtual bool                                            isDefinitionWeak(const Atom&){ return false; }
-       
-       
-       
+       virtual const char*                                     parentUmbrella()                        { return NULL; }
+       virtual std::vector<const char*>*       getAllowableClients()           { return NULL; }
+
 protected:
-                                                                               Reader() {}
+                                                                               Reader() : fSortOrder(0) {}
        virtual                                                         ~Reader() {}
+
+       unsigned int                                            fSortOrder;
 };
 
 class Segment
@@ -92,7 +123,7 @@ public:
        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; }
@@ -105,14 +136,14 @@ protected:
 
 class Reference;
 
-class Section 
+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;
@@ -120,33 +151,55 @@ protected:
 };
 
 
-class ContentWriter
-{
-public:
-       virtual void    write(uint64_t atomOffset, const void* buffer, uint64_t size) = 0;
-protected:
-                                                               ContentWriter() {}
-       virtual                                         ~ContentWriter() {}
-};
 
-class Atom 
+//
+// 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)
+//
+class Atom
 {
 public:
        enum Scope { scopeTranslationUnit, scopeLinkageUnit, scopeGlobal };
-       enum WeakImportSetting { kWeakUnset, kWeakImport, kNonWeakImport };
-       
+       enum DefinitionKind { kRegularDefinition, kWeakDefinition, kTentativeDefinition, kExternalDefinition, kExternalWeakDefinition };
+       enum SymbolTableInclusion { kSymbolTableNotIn, kSymbolTableIn, kSymbolTableInAndNeverStrip };
+
        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 bool                                                    isTentativeDefinition() const = 0;
-       virtual bool                                                    isWeakDefinition() const = 0;
-       virtual bool                                                    isCoalesableByName() const = 0;
-       virtual bool                                                    isCoalesableByValue() const = 0;
+       virtual DefinitionKind                                  getDefinitionKind() const = 0;
+       virtual SymbolTableInclusion                    getSymbolTableInclusion() const = 0;
        virtual bool                                                    isZeroFill() const = 0;
-       virtual bool                                                    dontDeadStrip() const = 0;
-       virtual bool                                                    dontStripName() const = 0;  // referenced dynamically
-       virtual bool                                                    isImportProxy() const = 0;
        virtual uint64_t                                                getSize() const = 0;
        virtual std::vector<ObjectFile::Reference*>&  getReferences() const = 0;
        virtual bool                                                    mustRemainInSection() const = 0;
@@ -154,34 +207,34 @@ public:
        virtual Segment&                                                getSegment() const = 0;
        virtual bool                                                    requiresFollowOnAtom() const = 0;
        virtual Atom&                                                   getFollowOnAtom() const = 0;
-       virtual std::vector<StabsInfo>*                 getStabsDebugInfo() const = 0;
+       virtual std::vector<LineInfo>*                  getLineInfo() const = 0;
        virtual uint8_t                                                 getAlignment() const = 0;
-       virtual WeakImportSetting                               getImportWeakness() const = 0;
        virtual void                                                    copyRawContent(uint8_t buffer[]) const = 0;
-       virtual void                                                    writeContent(bool finalLinkedImage, ContentWriter&) const = 0;
        virtual void                                                    setScope(Scope) = 0;
-       virtual void                                                    setImportWeakness(bool weakImport) = 0; 
 
-       
+
                        uint64_t                                                getSectionOffset() const        { return fSectionOffset; }
                        uint64_t                                                getSegmentOffset() const        { return fSegmentOffset; }
                        uint64_t                                                getAddress() const      { return fSection->getBaseAddress() + fSectionOffset; }
                        unsigned int                                    getSortOrder() const { return fSortOrder; }
                        class Section*                                  getSection() const { return fSection; }
+                       bool                                                    dontDeadStrip() const { return fDontDeadStrip; }
 
                        void                                                    setSegmentOffset(uint64_t offset) { fSegmentOffset = offset; }
                        void                                                    setSectionOffset(uint64_t offset) { fSectionOffset = offset; }
-                       void                                                    setSection(class Section* sect) { fSection = sect; } 
+                       void                                                    setSection(class Section* sect) { fSection = sect; }
                        unsigned int                                    setSortOrder(unsigned int order); // recursively sets follow-on atoms
+                       void                                                    setDontDeadStrip() { fDontDeadStrip = true; }
 
 protected:
-                                                                                       Atom() : fSegmentOffset(0), fSectionOffset(0), fSortOrder(0), fSection(NULL) {}
+                                                                                       Atom() : fSegmentOffset(0), fSectionOffset(0), fSortOrder(0), fSection(NULL), fDontDeadStrip(false) {}
                virtual                                                         ~Atom() {}
-               
+
                uint64_t                                                        fSegmentOffset;
                uint64_t                                                        fSectionOffset;
                unsigned int                                            fSortOrder;
                class Section*                                          fSection;
+               bool                                                            fDontDeadStrip;
 };
 
 
@@ -201,20 +254,35 @@ inline unsigned int Atom::setSortOrder(unsigned int order)
 
 
 
+//
+// 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 Kind { noFixUp, pointer, ppcFixupBranch24, ppcFixupBranch14, 
-                               ppcFixupPicBaseLow16, ppcFixupPicBaseLow14, ppcFixupPicBaseHigh16, 
-                               ppcFixupAbsLow16, ppcFixupAbsLow14, ppcFixupAbsHigh16, ppcFixupAbsHigh16AddLow,
-                               pointer32Difference, pointer64Difference, x86FixupBranch32 };
 
        virtual bool                    isTargetUnbound() const = 0;
        virtual bool                    isFromTargetUnbound() const = 0;
-       virtual bool                    requiresRuntimeFixUp(bool slideable) const = 0;
-       virtual bool                    isWeakReference() const = 0;
-       virtual bool                    isLazyReference() const = 0;
-       virtual Kind                    getKind() 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;
@@ -227,7 +295,7 @@ public:
        virtual void                    setTarget(Atom&, uint64_t offset) = 0;
        virtual void                    setFromTarget(Atom&) = 0;
        virtual const char*             getDescription() const = 0;
-       
+
 protected:
                                                        Reference() {}
        virtual                                 ~Reference() {}
@@ -238,9 +306,3 @@ protected:
 
 
 #endif // __OBJECTFILE__
-
-
-
-
-
-
index 350612b08b315064abdcab8dbc8069e1de3229e4..664bc416bdb99025661ec5c5fbcde8cced7771c6 100644 (file)
@@ -1,16 +1,16 @@
-/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+/* -*- 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,
  * 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 <sys/types.h>
 #include <sys/stat.h>
+#include <math.h>
 #include <fcntl.h>
 #include <vector>
 
 
 #include "Options.h"
 
- __attribute__((noreturn))
-void throwf(const char* format, ...) 
+void throwf(const char* format, ...)
 {
        va_list list;
        char*   p;
        va_start(list, format);
        vasprintf(&p, format, list);
        va_end(list);
-       
+
        const char*     t = p;
        throw t;
 }
 
-
 Options::Options(int argc, const char* argv[])
- : fOutputFile("a.out"), fArchitecture(CPU_TYPE_POWERPC64), fOutputKind(kDynamicExecutable), fBindAtLoad(false),
-       fStripLocalSymbols(false),  fKeepPrivateExterns(false),
-       fInterposable(false), fIgnoreOtherArchFiles(false), fForceSubtypeAll(false), fNameSpace(kTwoLevelNameSpace),
-       fDylibCompatVersion(0), fDylibCurrentVersion(0), fDylibInstallName(NULL), fEntryName("start"), fBaseAddress(0),
-       fExportMode(kExportDefault), fLibrarySearchMode(kSearchAllDirsForDylibsThenAllDirsForArchives),
-       fUndefinedTreatment(kUndefinedError), fMessagesPrefixedWithArchitecture(false), fPICTreatment(kPICError),
-       fWeakReferenceMismatchTreatment(kWeakReferenceMismatchError), 
-       fUmbrellaName(NULL), fInitFunctionName(NULL), fZeroPageSize(0x1000), fStackSize(0), fStackAddr(0), fMinimumHeaderPad(0),
-       fCommonsMode(kCommonsIgnoreDylibs), fWarnCommons(false), fVerbose(false)
+       : fOutputFile("a.out"), fArchitecture(0), fOutputKind(kDynamicExecutable), fBindAtLoad(false),
+         fStripLocalSymbols(false),  fKeepPrivateExterns(false),
+         fInterposable(false), fIgnoreOtherArchFiles(false), fForceSubtypeAll(false), fDeadStrip(kDeadStripOff),
+         fVersionMin(k10_1),fNameSpace(kTwoLevelNameSpace),
+         fDylibCompatVersion(0), fDylibCurrentVersion(0), fDylibInstallName(NULL), fEntryName("start"), fBaseAddress(0),
+         fExportMode(kExportDefault), fLibrarySearchMode(kSearchAllDirsForDylibsThenAllDirsForArchives),
+         fUndefinedTreatment(kUndefinedError), fMessagesPrefixedWithArchitecture(false), fPICTreatment(kError),
+         fWeakReferenceMismatchTreatment(kWeakReferenceMismatchError), fMultiplyDefinedDynamic(kWarning),
+         fMultiplyDefinedUnused(kSuppress), fWarnOnMultiplyDefined(false), fClientName(NULL),
+         fUmbrellaName(NULL), fInitFunctionName(NULL), fDotOutputFile(NULL), fExecutablePath(NULL),
+         fZeroPageSize(0x1000), fStackSize(0), fStackAddr(0), fExecutableStack(false), fMinimumHeaderPad(0),
+         fCommonsMode(kCommonsIgnoreDylibs), fWarnCommons(false), fVerbose(false), fKeepRelocations(false),
+         fEmitUUID(true),fWarnStabs(false),
+         fTraceDylibSearching(false), fPause(false), fStatistics(false), fPrintOptions(false)
 {
        this->parsePreCommandLineEnvironmentSettings();
        this->parse(argc, argv);
@@ -66,8 +70,7 @@ Options::~Options()
 {
 }
 
-
-ObjectFile::ReaderOptions& Options::readerOptions()
+const ObjectFile::ReaderOptions& Options::readerOptions()
 {
        return fReaderOptions;
 }
@@ -77,13 +80,11 @@ cpu_type_t Options::architecture()
        return fArchitecture;
 }
 
-
 const char*    Options::getOutputFilePath()
 {
        return fOutputFile;
 }
 
-
 std::vector<Options::FileInfo>& Options::getInputFiles()
 {
        return fInputFiles;
@@ -99,14 +100,14 @@ bool Options::stripLocalSymbols()
        return fStripLocalSymbols;
 }
 
-bool Options::stripDebugInfo()
+bool Options::bindAtLoad()
 {
-       return fReaderOptions.fStripDebugInfo;
+       return fBindAtLoad;
 }
 
-bool Options::bindAtLoad()
+bool Options::prebind()
 {
-       return fBindAtLoad;
+       return fPrebind;
 }
 
 bool Options::fullyLoadArchives()
@@ -121,7 +122,7 @@ Options::NameSpace Options::nameSpace()
 
 const char*    Options::installPath()
 {
-       if ( fDylibInstallName != NULL ) 
+       if ( fDylibInstallName != NULL )
                return fDylibInstallName;
        else
                return fOutputFile;
@@ -182,16 +183,46 @@ Options::UndefinedTreatment Options::undefinedTreatment()
        return fUndefinedTreatment;
 }
 
+Options::VersionMin Options::macosxVersionMin()
+{
+       return fVersionMin;
+}
+
 Options::WeakReferenceMismatchTreatment        Options::weakReferenceMismatchTreatment()
 {
        return fWeakReferenceMismatchTreatment;
 }
 
+Options::Treatment Options::multipleDefinitionsInDylibs()
+{
+       return fMultiplyDefinedDynamic;
+}
+
+Options::Treatment Options::overridingDefinitionInDependentDylib()
+{
+       return fMultiplyDefinedUnused;
+}
+
+bool Options::warnOnMultipleDefinitionsInObjectFiles()
+{
+       return fWarnOnMultiplyDefined;
+}
+
 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;
@@ -201,7 +232,7 @@ bool Options::hasCustomStack()
 {
        return (fStackSize != 0);
 }
-       
+
 uint64_t Options::customStackSize()
 {
        return fStackSize;
@@ -212,16 +243,31 @@ uint64_t Options::customStackAddr()
        return fStackAddr;
 }
 
+bool Options::hasExecutableStack()
+{
+       return fExecutableStack;
+}
+
 std::vector<const char*>& Options::initialUndefines()
 {
        return fInitialUndefines;
 }
 
+std::vector<const char*>& Options::traceSymbols()
+{
+       return fTraceSymbols;
+}
+
 const char*    Options::initFunctionName()
 {
        return fInitFunctionName;
 }
 
+const char*    Options::dotOutputFile()
+{
+       return fDotOutputFile;
+}
+
 bool Options::hasExportRestrictList()
 {
        return (fExportMode != kExportDefault);
@@ -242,7 +288,6 @@ std::vector<Options::SectionAlignment>&     Options::sectionAlignments()
        return fSectionAlignments;
 }
 
-
 Options::CommonsMode Options::commonsMode()
 {
        return fCommonsMode;
@@ -253,6 +298,31 @@ bool Options::warnCommons()
        return fWarnCommons;
 }
 
+bool Options::keepRelocations()
+{
+       return fKeepRelocations;
+}
+
+bool Options::emitUUID()
+{
+       return fEmitUUID;
+}
+
+bool Options::warnStabs()
+{
+       return fWarnStabs;
+}
+
+const char* Options::executablePath()
+{
+       return fExecutablePath;
+}
+
+Options::DeadStripMode Options::deadStrip()
+{
+       return fDeadStrip;
+}
+
 bool Options::shouldExport(const char* symbolName)
 {
        switch (fExportMode) {
@@ -266,7 +336,6 @@ bool Options::shouldExport(const char* symbolName)
        throw "internal error";
 }
 
-
 void Options::parseArch(const char* architecture)
 {
        if ( architecture == NULL )
@@ -277,22 +346,26 @@ void Options::parseArch(const char* architecture)
                fArchitecture = CPU_TYPE_POWERPC64;
        else if ( strcmp(architecture, "i386") == 0 )
                fArchitecture = CPU_TYPE_I386;
-       else 
+       else
                throw "-arch followed by unknown architecture name";
 }
 
 bool Options::checkForFile(const char* format, const char* dir, const char* rootName, FileInfo& result)
 {
        struct stat statBuffer;
-       char possiblePath[strlen(dir)+strlen(rootName)+20];
+       char possiblePath[strlen(dir)+strlen(rootName)+strlen(format)+8];
        sprintf(possiblePath, format,  dir, rootName);
-       if ( stat(possiblePath, &statBuffer) == 0 ) {
+       bool found = (stat(possiblePath, &statBuffer) == 0);
+       if ( fTraceDylibSearching )
+               printf("[Logging for XBS]%sfound library: '%s'\n", (found ? " " : " not "), possiblePath);
+       if ( found ) {
                result.path = strdup(possiblePath);
                result.fileLen = statBuffer.st_size;
+               result.modTime = statBuffer.st_mtime;
                return true;
        }
        return false;
-} 
+}
 
 
 Options::FileInfo Options::findLibrary(const char* rootName)
@@ -301,7 +374,9 @@ Options::FileInfo Options::findLibrary(const char* rootName)
        const int rootNameLen = strlen(rootName);
        // if rootName ends in .o there is no .a vs .dylib choice
        if ( (rootNameLen > 3) && (strcmp(&rootName[rootNameLen-2], ".o") == 0) ) {
-               for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin(); it != fLibrarySearchPaths.end(); it++) {
+               for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin();
+                        it != fLibrarySearchPaths.end();
+                        it++) {
                        const char* dir = *it;
                        if ( checkForFile("%s/%s", dir, rootName, result) )
                                return result;
@@ -310,17 +385,21 @@ Options::FileInfo Options::findLibrary(const char* rootName)
        else {
                bool lookForDylibs = ( fOutputKind != Options::kDyld);
                switch ( fLibrarySearchMode ) {
-                       case kSearchAllDirsForDylibsThenAllDirsForArchives:
+               case kSearchAllDirsForDylibsThenAllDirsForArchives:
                                // first look in all directories for just for dylibs
                                if ( lookForDylibs ) {
-                                       for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin(); it != fLibrarySearchPaths.end(); it++) {
+                                       for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin();
+                                                it != fLibrarySearchPaths.end();
+                                                it++) {
                                                const char* dir = *it;
                                                if ( checkForFile("%s/lib%s.dylib", dir, rootName, result) )
                                                        return result;
                                        }
                                }
                                // next look in all directories for just for archives
-                               for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin(); it != fLibrarySearchPaths.end(); it++) {
+                               for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin();
+                                        it != fLibrarySearchPaths.end();
+                                        it++) {
                                        const char* dir = *it;
                                        if ( checkForFile("%s/lib%s.a", dir, rootName, result) )
                                                return result;
@@ -329,7 +408,9 @@ Options::FileInfo Options::findLibrary(const char* rootName)
 
                        case kSearchDylibAndArchiveInEachDir:
                                // look in each directory for just for a dylib then for an archive
-                               for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin(); it != fLibrarySearchPaths.end(); it++) {
+                               for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin();
+                                        it != fLibrarySearchPaths.end();
+                                        it++) {
                                        const char* dir = *it;
                                        if ( lookForDylibs && checkForFile("%s/lib%s.dylib", dir, rootName, result) )
                                                return result;
@@ -347,7 +428,11 @@ Options::FileInfo Options::findFramework(const char* rootName)
 {
        struct stat statBuffer;
        const int rootNameLen = strlen(rootName);
-       for (std::vector<const char*>::iterator it = fFrameworkSearchPaths.begin(); it != fFrameworkSearchPaths.end(); it++) {
+       for (std::vector<const char*>::iterator it = fFrameworkSearchPaths.begin();
+                it != fFrameworkSearchPaths.end();
+                it++) {
+               // ??? Shouldn't we be using String here and just initializing it?
+               // ??? Use str.c_str () to pull out the string for the stat call.
                const char* dir = *it;
                char possiblePath[strlen(dir)+2*rootNameLen+20];
                strcpy(possiblePath, dir);
@@ -355,10 +440,15 @@ Options::FileInfo Options::findFramework(const char* rootName)
                strcat(possiblePath, rootName);
                strcat(possiblePath, ".framework/");
                strcat(possiblePath, rootName);
-               if ( stat(possiblePath, &statBuffer) == 0 ) {
+               bool found = (stat(possiblePath, &statBuffer) == 0);
+               if ( fTraceDylibSearching )
+                       printf("[Logging for XBS]%sfound framework: '%s'\n",
+                                  (found ? " " : " not "), possiblePath);
+               if ( found ) {
                        FileInfo result;
                        result.path = strdup(possiblePath);
                        result.fileLen = statBuffer.st_size;
+                       result.modTime = statBuffer.st_mtime;
                        return result;
                }
        }
@@ -369,11 +459,12 @@ Options::FileInfo Options::findFile(const char* path)
 {
        FileInfo result;
        struct stat statBuffer;
-       
+
        // if absolute path and not a .o file, the use SDK prefix
        if ( (path[0] == '/') && (strcmp(&path[strlen(path)-2], ".o") != 0) ) {
                const int pathLen = strlen(path);
                for (std::vector<const char*>::iterator it = fSDKPaths.begin(); it != fSDKPaths.end(); it++) {
+                       // ??? Shouldn't we be using String here?
                        const char* sdkPathDir = *it;
                        const int sdkPathDirLen = strlen(sdkPathDir);
                        char possiblePath[sdkPathDirLen+pathLen+4];
@@ -384,6 +475,7 @@ Options::FileInfo Options::findFile(const char* path)
                        if ( stat(possiblePath, &statBuffer) == 0 ) {
                                result.path = strdup(possiblePath);
                                result.fileLen = statBuffer.st_size;
+                               result.modTime = statBuffer.st_mtime;
                                return result;
                        }
                }
@@ -392,8 +484,27 @@ Options::FileInfo Options::findFile(const char* path)
        if ( stat(path, &statBuffer) == 0 ) {
                result.path = strdup(path);
                result.fileLen = statBuffer.st_size;
+               result.modTime = statBuffer.st_mtime;
                return result;
        }
+
+       // try @executable_path substitution
+       if ( (strncmp(path, "@executable_path/", 17) == 0) && (fExecutablePath != NULL) ) {
+               char newPath[strlen(fExecutablePath) + strlen(path)];
+               strcpy(newPath, fExecutablePath);
+               char* addPoint = strrchr(newPath,'/');
+               if ( addPoint != NULL )
+                       strcpy(&addPoint[1], &path[17]);
+               else
+                       strcpy(newPath, &path[17]);
+               if ( stat(newPath, &statBuffer) == 0 ) {
+                       result.path = strdup(newPath);
+                       result.fileLen = statBuffer.st_size;
+                       result.modTime = statBuffer.st_mtime;
+                       return result;
+               }
+       }
+
        // not found
        throwf("file not found: %s", path);
 }
@@ -402,16 +513,16 @@ Options::FileInfo Options::findFile(const char* path)
 void Options::loadFileList(const char* fileOfPaths)
 {
        FILE* file = fopen(fileOfPaths, "r");
-       if ( file == NULL ) 
+       if ( file == NULL )
                throwf("-filelist file not found: %s\n", fileOfPaths);
-       
+
        char path[1024];
        while ( fgets(path, 1024, file) != NULL ) {
                path[1023] = '\0';
                char* eol = strchr(path, '\n');
                if ( eol != NULL )
                        *eol = '\0';
-                       
+
                fInputFiles.push_back(findFile(path));
        }
        fclose(file);
@@ -429,53 +540,68 @@ void Options::loadExportFile(const char* fileOfExports, const char* option, Name
        char* p = (char*)malloc(stat_buf.st_size);
        if ( p == NULL )
                throwf("can't process %s file: %s", option, fileOfExports);
-       
+
        if ( read(fd, p, stat_buf.st_size) != stat_buf.st_size )
                throwf("can't read %s file: %s", option, fileOfExports);
-       
+
        ::close(fd);
-       
+
        // parse into symbols and add to hash_set
        char * const end = &p[stat_buf.st_size];
        enum { lineStart, inSymbol, inComment } state = lineStart;
        char* symbolStart = NULL;
        for (char* s = p; s < end; ++s ) {
                switch ( state ) {
-                       case lineStart:
-                               if ( *s =='#' ) {
-                                       state = inComment;
-                               }
-                               else if ( !isspace(*s) ) {
-                                       state = inSymbol;
-                                       symbolStart = s;
-                               }
-                               break;
-                       case inSymbol:
-                               if ( *s == '\n' ) {
-                                       *s = '\0';
-                                       // removing any trailing spaces
-                                       char* last = s-1;
-                                       while ( isspace(*last) ) {
-                                               *last = '\0';
-                                               --last;
-                                       }
-                                       set.insert(symbolStart);
-                                       symbolStart = NULL;
-                                       state = lineStart;
+               case lineStart:
+                       if ( *s =='#' ) {
+                               state = inComment;
+                       }
+                       else if ( !isspace(*s) ) {
+                               state = inSymbol;
+                               symbolStart = s;
+                       }
+                       break;
+               case inSymbol:
+                       if ( *s == '\n' ) {
+                               *s = '\0';
+                               // removing any trailing spaces
+                               char* last = s-1;
+                               while ( isspace(*last) ) {
+                                       *last = '\0';
+                                       --last;
                                }
-                               break;
-                       case inComment:
-                               if ( *s == '\n' )
-                                       state = lineStart;
-                               break;
+                               set.insert(symbolStart);
+                               symbolStart = NULL;
+                               state = lineStart;
+                       }
+                       break;
+               case inComment:
+                       if ( *s == '\n' )
+                               state = lineStart;
+                       break;
+               }
+       }
+       if ( state == inSymbol ) {
+               fprintf(stderr, "ld64 warning: missing line-end at end of file \"%s\"\n", fileOfExports);
+               int len = end-symbolStart+1;
+               char* temp = new char[len];
+               strlcpy(temp, symbolStart, len);
+
+               // remove any trailing spaces
+               char* last = &temp[len-2];
+               while ( isspace(*last) ) {
+                       *last = '\0';
+                       --last;
                }
+               set.insert(temp);
        }
+
        // Note: we do not free() the malloc buffer, because the strings are used by the export-set hash table
 }
 
 void Options::setUndefinedTreatment(const char* treatment)
 {
-       if ( treatment == NULL ) 
+       if ( treatment == NULL )
                throw "-undefined missing [ warning | error | suppress | dynamic_lookup ]";
 
        if ( strcmp(treatment, "warning") == 0 )
@@ -490,37 +616,43 @@ void Options::setUndefinedTreatment(const char* treatment)
                throw "invalid option to -undefined [ warning | error | suppress | dynamic_lookup ]";
 }
 
-void Options::setReadOnlyRelocTreatment(const char* treatment)
+Options::Treatment Options::parseTreatment(const char* treatment)
 {
-       if ( treatment == NULL ) 
-               throw "-read_only_relocs missing [ warning | error | suppress ]";
+       if ( treatment == NULL )
+               return kNULL;
 
        if ( strcmp(treatment, "warning") == 0 )
-               throw "-read_only_relocs warning not supported";
+               return kWarning;
+       else if ( strcmp(treatment, "error") == 0 )
+               return kError;
        else if ( strcmp(treatment, "suppress") == 0 )
-               throw "-read_only_relocs suppress not supported";
-       else if ( strcmp(treatment, "error") != 0 )
-               throw "invalid option to -read_only_relocs [ warning | error | suppress | dynamic_lookup ]";
+               return kSuppress;
+       else
+               return kInvalid;
 }
 
-void Options::setPICTreatment(const char* treatment)
-{
-       if ( treatment == NULL ) 
-               throw "-sect_diff_relocs missing [ warning | error | suppress ]";
-
-       if ( strcmp(treatment, "warning") == 0 )
-               fPICTreatment = kPICWarning;
-       else if ( strcmp(treatment, "error") == 0 )
-               fPICTreatment = kPICError;
-       else if ( strcmp(treatment, "suppress") == 0 )
-               fPICTreatment = kPICSuppress;
+void Options::setVersionMin(const char* version)
+{
+       if ( version == NULL )
+               throw "-macosx_version_min argument missing";
+
+       if ( strcmp(version, "10.1") == 0 )
+               fVersionMin = k10_1;
+       else if ( strcmp(version, "10.2") == 0)
+               fVersionMin = k10_2;
+       else if ( strcmp(version, "10.3") == 0)
+               fVersionMin = k10_3;
+       else if ( strcmp(version, "10.4") == 0)
+               fVersionMin = k10_4;
+       else if ( strcmp(version, "10.5") == 0)
+               fVersionMin = k10_5;
        else
-               throw "invalid option to -sect_diff_relocs [ warning | error | suppress ]";
+               fprintf(stderr, "ld64: unknown option to -macosx_version_min");
 }
 
 void Options::setWeakReferenceMismatchTreatment(const char* treatment)
 {
-       if ( treatment == NULL ) 
+       if ( treatment == NULL )
                throw "-weak_reference_mismatches missing [ error | weak | non-weak ]";
 
        if ( strcmp(treatment, "error") == 0 )
@@ -535,7 +667,7 @@ void Options::setWeakReferenceMismatchTreatment(const char* treatment)
 
 Options::CommonsMode Options::parseCommonsTreatment(const char* mode)
 {
-       if ( mode == NULL ) 
+       if ( mode == NULL )
                throw "-commons missing [ ignore_dylibs | use_dylibs | error ]";
 
        if ( strcmp(mode, "ignore_dylibs") == 0 )
@@ -548,22 +680,12 @@ Options::CommonsMode Options::parseCommonsTreatment(const char* mode)
                throw "invalid option to -commons [ ignore_dylibs | use_dylibs | error ]";
 }
 
-
 void Options::setDylibInstallNameOverride(const char* paths)
 {
 
 
 }
 
-void Options::setExecutablePath(const char* path)
-{
-
-
-}
-
-
-
-
 uint64_t Options::parseAddress(const char* addr)
 {
        char* endptr;
@@ -571,10 +693,8 @@ uint64_t Options::parseAddress(const char* addr)
        return result;
 }
 
-
-
 //
-// Parses number of form X[.Y[.Z]] into a uint32_t where the nibbles are xxxx.yy.zz 
+// Parses number of form X[.Y[.Z]] into a uint32_t where the nibbles are xxxx.yy.zz
 //
 //
 uint32_t Options::parseVersionNumber(const char* versionString)
@@ -605,8 +725,12 @@ void Options::addSection(const char* segment, const char* section, const char* p
 {
        if ( strlen(segment) > 16 )
                throw "-seccreate segment name max 16 chars";
-       if ( strlen(section) > 16 )
-               throw "-seccreate section name max 16 chars";
+       if ( strlen(section) > 16 ) {
+               char* tmp = strdup(section);
+               tmp[16] = '\0';
+               fprintf(stderr, "ld64 warning: -seccreate section name (%s) truncated to 16 chars (%s)\n", section, tmp);
+               section = tmp;
+       }
 
        // read in whole file
        int fd = ::open(path, O_RDONLY, 0);
@@ -620,7 +744,7 @@ void Options::addSection(const char* segment, const char* section, const char* p
        if ( read(fd, p, stat_buf.st_size) != stat_buf.st_size )
                throwf("can't read -sectcreate file: %s", path);
        ::close(fd);
-       
+
        // record section to create
        ExtraSection info = { segment, section, path, (uint8_t*)p, stat_buf.st_size };
        fExtraSections.push_back(info);
@@ -633,33 +757,59 @@ void Options::addSectionAlignment(const char* segment, const char* section, cons
        if ( strlen(section) > 16 )
                throw "-sectalign section name max 16 chars";
 
+       // argument to -sectalign is a hexadecimal number
        char* endptr;
        unsigned long value = strtoul(alignmentStr, &endptr, 16);
        if ( *endptr != '\0')
                throw "argument for -sectalign is not a hexadecimal number";
        if ( value > 0x8000 )
                throw "argument for -sectalign must be less than or equal to 0x8000";
-       uint8_t alignment = 0;
-       for(unsigned long x=value; x != 1; x >>= 1)
-               ++alignment;
-       if ( (unsigned long)(1 << alignment) != value )
-               throw "argument for -sectalign is not a power of two";
+       if ( value == 0 ) {
+               fprintf(stderr, "ld64 warning: zero is not a valid -sectalign\n");
+               value = 1;
+       }
+       
+       // alignment is power of 2 (e.g. page alignment = 12)
+       uint8_t alignment = (uint8_t)log2(value);
+       
+       if ( (unsigned long)(1 << alignment) != value ) {
+               fprintf(stderr, "ld64 warning: alignment for -sectalign %s %s is not a power of two, using 0x%X\n", 
+                       segment, section, 1 << alignment);
+       }
 
        SectionAlignment info = { segment, section, alignment };
        fSectionAlignments.push_back(info);
 }
 
-
+//
+// Process all command line arguments.
+//
+// The only error checking done here is that each option is valid and if it has arguments
+// that they too are valid.
+//
+// The general rule is "last option wins", i.e. if both -bundle and -dylib are specified,
+// whichever was last on the command line is used.
+//
+// Error check for invalid combinations of options is done in checkIllegalOptionCombinations()
+//
 void Options::parse(int argc, const char* argv[])
 {
        // pass one builds search list from -L and -F options
        this->buildSearchPaths(argc, argv);
-       
+
+       // reduce re-allocations
+       fInputFiles.reserve(32);
+
        // pass two parse all other options
        for(int i=1; i < argc; ++i) {
                const char* arg = argv[i];
-               
+
                if ( arg[0] == '-' ) {
+
+                       // Since we don't care about the files passed, just the option names, we do this here.
+                       if (fPrintOptions)
+                               fprintf (stderr, "[Logging ld64 options]\t%s\n", arg);
+
                        if ( (arg[1] == 'L') || (arg[1] == 'F') ) {
                                // previously handled by buildSearchPaths()
                        }
@@ -694,11 +844,15 @@ void Options::parse(int argc, const char* argv[])
                        else if ( arg[1] == 'l' ) {
                                fInputFiles.push_back(findLibrary(&arg[2]));
                        }
-                       else if ( strcmp(arg, "-weak-l") == 0 ) {
-                               FileInfo info = findLibrary(&arg[2]);
+                       // This causes a dylib to be weakly bound at
+                       // link time.  This corresponds to weak_import.
+                       else if ( strncmp(arg, "-weak-l", 7) == 0 ) {
+                               FileInfo info = findLibrary(&arg[7]);
                                info.options.fWeakImport = true;
                                fInputFiles.push_back(info);
                        }
+                       // Avoid lazy binding.
+                       // ??? Deprecate.
                        else if ( strcmp(arg, "-bind_at_load") == 0 ) {
                                fBindAtLoad = true;
                        }
@@ -708,15 +862,21 @@ void Options::parse(int argc, const char* argv[])
                        else if ( strcmp(arg, "-flat_namespace") == 0 ) {
                                fNameSpace = kFlatNameSpace;
                        }
+                       // Also sets a bit to ensure dyld causes everything
+                       // in the namespace to be flat.
+                       // ??? Deprecate
                        else if ( strcmp(arg, "-force_flat_namespace") == 0 ) {
                                fNameSpace = kForceFlatNameSpace;
                        }
+                       // Similar to --whole-archive.
                        else if ( strcmp(arg, "-all_load") == 0 ) {
                                fReaderOptions.fFullyLoadArchives = true;
                        }
+                       // Similar to --whole-archive, but for all ObjC classes.
                        else if ( strcmp(arg, "-ObjC") == 0 ) {
                                fReaderOptions.fLoadObjcClassesInArchives = true;
                        }
+                       // Library versioning.
                        else if ( strcmp(arg, "-dylib_compatibility_version") == 0 ) {
                                fDylibCompatVersion = parseVersionNumber(argv[++i]);
                        }
@@ -727,32 +887,41 @@ void Options::parse(int argc, const char* argv[])
                                parseSectionOrderFile(argv[i+1], argv[i+2], argv[i+3]);
                                i += 3;
                        }
+                       // ??? Deprecate segcreate.
+                       // -sectcreate puts whole files into a section in the output.
                        else if ( (strcmp(arg, "-sectcreate") == 0) || (strcmp(arg, "-segcreate") == 0) ) {
                                addSection(argv[i+1], argv[i+2], argv[i+3]);
                                i += 3;
                        }
+                       // Since we have a full path in binary/library names we need to be able to override it.
                        else if ( (strcmp(arg, "-dylib_install_name") == 0) || (strcmp(arg, "-dylinker_install_name") == 0) ) {
                                fDylibInstallName = argv[++i];
                        }
+                       // Sets the base address of the output.
                        else if ( strcmp(arg, "-seg1addr") == 0 ) {
                                fBaseAddress = parseAddress(argv[++i]);
                        }
                        else if ( strcmp(arg, "-e") == 0 ) {
                                fEntryName = argv[++i];
                        }
+                       // Same as -@ from the FSF linker.
                        else if ( strcmp(arg, "-filelist") == 0 ) {
                                 loadFileList(argv[++i]);
                        }
                        else if ( strcmp(arg, "-keep_private_externs") == 0 ) {
                                 fKeepPrivateExterns = true;
                        }
+                       // ??? Deprecate
                        else if ( strcmp(arg, "-final_output") == 0 ) {
                                 ++i;
                                // ignore for now
                        }
+                       // Ensure that all calls to exported symbols go through lazy pointers.  Multi-module
+                       // just ensures that this happens for cross object file boundaries.
                        else if ( (strcmp(arg, "-interposable") == 0) || (strcmp(arg, "-multi_module") == 0)) {
                                 fInterposable = true;
                        }
+                       // Default for -interposable/-multi_module/-single_module.
                        else if ( strcmp(arg, "-single_module") == 0 ) {
                                 fInterposable = false;
                        }
@@ -768,12 +937,14 @@ void Options::parse(int argc, const char* argv[])
                                fExportMode = kDontExportSome;
                                loadExportFile(argv[++i], "-unexported_symbols_list", fDontExportSymbols);
                        }
+                       // ??? Deprecate
                        else if ( strcmp(arg, "-no_arch_warnings") == 0 ) {
                                 fIgnoreOtherArchFiles = true;
                        }
                        else if ( strcmp(arg, "-force_cpusubtype_ALL") == 0 ) {
                                 fForceSubtypeAll = true;
                        }
+                       // Similar to -weak-l but uses the absolute path name to the library.
                        else if ( strcmp(arg, "-weak_library") == 0 ) {
                                FileInfo info = findFile(argv[++i]);
                                info.options.fWeakImport = true;
@@ -787,75 +958,119 @@ void Options::parse(int argc, const char* argv[])
                                info.options.fWeakImport = true;
                                fInputFiles.push_back(info);
                        }
+                       // ??? Deprecate when we get -Bstatic/-Bdynamic.
                        else if ( strcmp(arg, "-search_paths_first") == 0 ) {
                                fLibrarySearchMode = kSearchDylibAndArchiveInEachDir;
                        }
                        else if ( strcmp(arg, "-undefined") == 0 ) {
                                 setUndefinedTreatment(argv[++i]);
                        }
+                       // Debugging output flag.
                        else if ( strcmp(arg, "-arch_multiple") == 0 ) {
                                 fMessagesPrefixedWithArchitecture = true;
                        }
+                       // Specify what to do with relocations in read only
+                       // sections like .text.  Could be errors, warnings,
+                       // or suppressed.  Currently we do nothing with the
+                       // flag.
                        else if ( strcmp(arg, "-read_only_relocs") == 0 ) {
-                                setReadOnlyRelocTreatment(argv[++i]);
+                               Treatment temp = parseTreatment(argv[++i]);
+
+                               if ( temp == kNULL )
+                                       throw "-read_only_relocs missing [ warning | error | suppress ]";
+                               else if ( temp == kInvalid )
+                                       throw "invalid option to -read_only_relocs [ warning | error | suppress ]";
                        }
+                       // Specifies whether or not there are intra section
+                       // relocations and what to do when found. Could be
+                       // errors, warnings, or suppressed.
                        else if ( strcmp(arg, "-sect_diff_relocs") == 0 ) {
-                                setPICTreatment(argv[++i]);
+                               fPICTreatment = parseTreatment(argv[++i]);
+
+                               if ( fPICTreatment == kNULL )
+                                       throw "-sect_diff_relocs missing [ warning | error | suppress ]";
+                               else if ( fPICTreatment == kInvalid )
+                                       throw "invalid option to -sect_diff_relocs [ warning | error | suppress ]";
                        }
+                       // Warn, error or make strong a mismatch between weak
+                       // and non-weak references.
                        else if ( strcmp(arg, "-weak_reference_mismatches") == 0 ) {
                                 setWeakReferenceMismatchTreatment(argv[++i]);
                        }
+                       // For a deployment target of 10.3 and earlier ld64 will
+                       // prebind an executable with 0s in all addresses that
+                       // are prebound.  This can then be fixed up by update_prebinding
+                       // later.  Prebinding is less useful on 10.4 and greater.
                        else if ( strcmp(arg, "-prebind") == 0 ) {
-                                 // FIX FIX
+                               fPrebind = true;
                        }
                        else if ( strcmp(arg, "-noprebind") == 0 ) {
-                                 // FIX FIX
+                               fPrebind = false;
                        }
+                       // ??? Deprecate
                        else if ( strcmp(arg, "-prebind_allow_overlap") == 0 ) {
-                                 // FIX FIX
+                                 // Do not handle and suppress warnings always.
                        }
+                       // ??? Deprecate
                        else if ( strcmp(arg, "-prebind_all_twolevel_modules") == 0 ) {
-                                 // FIX FIX
+                                 // Ignore.
                        }
+                       // ??? Deprecate
                        else if ( strcmp(arg, "-noprebind_all_twolevel_modules") == 0 ) {
-                                 // FIX FIX
+                                 // Ignore.
                        }
+                       // Sets a bit in the main executable only that causes fix_prebinding
+                       // not to run.  This is always set.
                        else if ( strcmp(arg, "-nofixprebinding") == 0 ) {
-                                 // FIX FIX
+                                 // Ignore.
                        }
+                       // This should probably be deprecated when we respect -L and -F
+                       // when searching for libraries.
                        else if ( strcmp(arg, "-dylib_file") == 0 ) {
                                 setDylibInstallNameOverride(argv[++i]);
                        }
+                       // Allows us to rewrite full paths to be relocatable based on
+                       // the path name of the executable.
                        else if ( strcmp(arg, "-executable_path") == 0 ) {
-                                setExecutablePath(argv[++i]);
+                                fExecutablePath = argv[++i];
+                                if ( (fExecutablePath == NULL) || (fExecutablePath[0] == '-') )
+                                       throw "-executable_path missing <path>";
                        }
+                       // ??? Deprecate
+                       // Aligns all segments to the power of 2 boundary specified.
                        else if ( strcmp(arg, "-segalign") == 0 ) {
-                               // FIX FIX
-                               ++i; 
+                               // Ignore.
+                               ++i;
                        }
+                       // Puts a specified segment at a particular address that must
+                       // be a multiple of the segment alignment.
                        else if ( strcmp(arg, "-segaddr") == 0 ) {
                                // FIX FIX
-                               i += 2; 
+                               i += 2;
                        }
+                       // ??? Deprecate when we deprecate split-seg.
                        else if ( strcmp(arg, "-segs_read_only_addr") == 0 ) {
-                               // FIX FIX
-                               ++i; 
+                               // Ignore.
+                               ++i;
                        }
+                       // ??? Deprecate when we deprecate split-seg.
                        else if ( strcmp(arg, "-segs_read_write_addr") == 0 ) {
-                               // FIX FIX
-                               ++i; 
+                               // Ignore.
+                               ++i;
                        }
+                       // ??? Deprecate when we get rid of basing at build time.
                        else if ( strcmp(arg, "-seg_addr_table") == 0 ) {
-                               // FIX FIX
-                               ++i; 
+                               // Ignore.
+                               ++i;
                        }
+                       // ??? Deprecate.
                        else if ( strcmp(arg, "-seg_addr_table_filename") == 0 ) {
-                               // FIX FIX
-                               ++i; 
+                               // Ignore.
+                               ++i;
                        }
                        else if ( strcmp(arg, "-segprot") == 0 ) {
                                // FIX FIX
-                               i += 3; 
+                               i += 3;
                        }
                        else if ( strcmp(arg, "-pagezero_size") == 0 ) {
                                fZeroPageSize = parseAddress(argv[++i]);
@@ -867,6 +1082,9 @@ void Options::parse(int argc, const char* argv[])
                        else if ( strcmp(arg, "-stack_size") == 0 ) {
                                fStackSize = parseAddress(argv[++i]);
                        }
+                       else if ( strcmp(arg, "-allow_stack_execute") == 0 ) {
+                               fExecutableStack = true;
+                       }
                        else if ( strcmp(arg, "-sectalign") == 0 ) {
                                addSectionAlignment(argv[i+1], argv[i+2], argv[i+3]);
                                i += 3;
@@ -888,30 +1106,53 @@ void Options::parse(int argc, const char* argv[])
                        else if ( strcmp(arg, "-twolevel_namespace_hints") == 0 ) {
                                // FIX FIX
                        }
+                       // Use this flag to set default behavior for deployement targets.
                        else if ( strcmp(arg, "-macosx_version_min") == 0 ) {
-                               // This flag isn't needed yet, so just ignore it.
-                               ++i;
+                               setVersionMin(argv[++i]);
                        }
+                       // This option (unlike -m below) only affects how we warn
+                       // on multiple definitions inside dynamic libraries.
                        else if ( strcmp(arg, "-multiply_defined") == 0 ) {
-                               // FIX FIX
-                               ++i;
+                               fMultiplyDefinedDynamic = parseTreatment(argv[++i]);
+
+                               if ( fMultiplyDefinedDynamic == kNULL )
+                                       throw "-multiply_defined missing [ warning | error | suppress ]";
+                               else if ( fMultiplyDefinedDynamic == kInvalid )
+                                       throw "invalid option to -multiply_defined [ warning | error | suppress ]";
                        }
                        else if ( strcmp(arg, "-multiply_defined_unused") == 0 ) {
-                               // FIX FIX
-                               ++i;
+                               fMultiplyDefinedUnused = parseTreatment(argv[++i]);
+
+                               if ( fMultiplyDefinedUnused == kNULL )
+                                       throw "-multiply_defined_unused missing [ warning | error | suppress ]";
+                               else if ( fMultiplyDefinedUnused == kInvalid )
+                                       throw "invalid option to -multiply_defined_unused [ warning | error | suppress ]";
                        }
                        else if ( strcmp(arg, "-nomultidefs") == 0 ) {
                                 // FIX FIX
                        }
-                       else if ( arg[1] == 'y' ) {
-                                // FIX FIX
+                       // Display each file in which the argument symbol appears and whether
+                       // the file defines or references it.  This option takes an argument
+                       // as -y<symbol> note that there is no space.
+                       else if ( strncmp(arg, "-y", 2) == 0 ) {
+                               const char* name = &arg[2];
+
+                               if ( name == NULL )
+                                       throw "-y missing argument";
+
+                               fTraceSymbols.push_back(name);
                        }
+                       // Same output as -y, but output <arg> number of undefined symbols only.
                        else if ( strcmp(arg, "-Y") == 0 ) {
-                                ++i;
-                                // FIX FIX
+                               char* endptr;
+                               fLimitUndefinedSymbols = strtoul (argv[++i], &endptr, 10);
+
+                               if(*endptr != '\0')
+                                       throw "invalid argument for -Y [decimal number]";
                        }
+                       // This option affects all objects linked into the final result.
                        else if ( strcmp(arg, "-m") == 0 ) {
-                                // FIX FIX
+                               fWarnOnMultiplyDefined = true;
                        }
                        else if ( strcmp(arg, "-whyload") == 0 ) {
                                 // FIX FIX
@@ -922,37 +1163,42 @@ void Options::parse(int argc, const char* argv[])
                                        throw "-u missing argument";
                                fInitialUndefines.push_back(name);
                        }
-                       else if ( strcmp(arg, "-i") == 0 ) {
-                                  // FIX FIX
-                       }
                        else if ( strcmp(arg, "-U") == 0 ) {
                                 // FIX FIX
-                                ++i;  
+                                ++i;
                        }
                        else if ( strcmp(arg, "-s") == 0 ) {
-                               // FIX FIX
+                               fStripLocalSymbols = true;
+                               fReaderOptions.fDebugInfoStripping = ObjectFile::ReaderOptions::kDebugInfoNone;
                        }
                        else if ( strcmp(arg, "-x") == 0 ) {
-                               // FIX FIX
+                               fStripLocalSymbols = true;
                        }
                        else if ( strcmp(arg, "-S") == 0 ) {
-                               // FIX FIX
+                               fReaderOptions.fDebugInfoStripping = ObjectFile::ReaderOptions::kDebugInfoNone;
                        }
                        else if ( strcmp(arg, "-X") == 0 ) {
                                // FIX FIX
                        }
                        else if ( strcmp(arg, "-Si") == 0 ) {
-                               // FIX FIX
+                               fReaderOptions.fDebugInfoStripping = ObjectFile::ReaderOptions::kDebugInfoFull;
                        }
                        else if ( strcmp(arg, "-b") == 0 ) {
                                // FIX FIX
                        }
                        else if ( strcmp(arg, "-Sn") == 0 ) {
-                               // FIX FIX
+                               fReaderOptions.fDebugInfoStripping = ObjectFile::ReaderOptions::kDebugInfoFull;
+                       }
+                       else if ( strcmp(arg, "-Sp") == 0 ) {
+                               fReaderOptions.fDebugInfoStripping = ObjectFile::ReaderOptions::kDebugInfoMinimal;
                        }
                        else if ( strcmp(arg, "-dead_strip") == 0 ) {
-                                // FIX FIX
-                                fprintf(stderr, "ld64: warning -dead_strip not yet supported for 64-bit code\n");
+                               //fDeadStrip = kDeadStripOnPlusUnusedInits;
+                                fprintf(stderr, "ld64: warning -dead_strip not yet supported in ld64\n");
+                       }
+                       else if ( strcmp(arg, "-no_dead_strip_inits_and_terms") == 0 ) {
+                               //fDeadStrip = kDeadStripOn;
+                                fprintf(stderr, "ld64: warning -dead_strip not yet supported in ld64\n");
                        }
                        else if ( strcmp(arg, "-w") == 0 ) {
                                // FIX FIX
@@ -980,7 +1226,7 @@ void Options::parse(int argc, const char* argv[])
                        }
                        else if ( strcmp(arg, "-A") == 0 ) {
                                 // FIX FIX
-                                ++i;  
+                                ++i;
                        }
                        else if ( strcmp(arg, "-umbrella") == 0 ) {
                                const char* name = argv[++i];
@@ -989,12 +1235,20 @@ void Options::parse(int argc, const char* argv[])
                                fUmbrellaName = name;
                        }
                        else if ( strcmp(arg, "-allowable_client") == 0 ) {
-                                // FIX FIX
-                                ++i;  
+                               const char* name = argv[++i];
+
+                               if ( name == NULL )
+                                       throw "-allowable_client missing argument";
+
+                               fAllowableClients.push_back(name);
                        }
                        else if ( strcmp(arg, "-client_name") == 0 ) {
-                                // FIX FIX
-                                ++i;  
+                               const char* name = argv[++i];
+
+                               if ( name == NULL )
+                                       throw "-client_name missing argument";
+
+                               fClientName = name;
                        }
                        else if ( strcmp(arg, "-sub_umbrella") == 0 ) {
                                const char* name = argv[++i];
@@ -1014,12 +1268,30 @@ void Options::parse(int argc, const char* argv[])
                                        throw "-init missing argument";
                                fInitFunctionName = name;
                        }
+                       else if ( strcmp(arg, "-dot") == 0 ) {
+                               const char* name = argv[++i];
+                               if ( name == NULL )
+                                       throw "-dot missing argument";
+                               fDotOutputFile = name;
+                       }
                        else if ( strcmp(arg, "-warn_commons") == 0 ) {
                                fWarnCommons = true;
                        }
                        else if ( strcmp(arg, "-commons") == 0 ) {
                                fCommonsMode = parseCommonsTreatment(argv[++i]);
                        }
+                       else if ( strcmp(arg, "-keep_relocs") == 0 ) {
+                               fKeepRelocations = true;
+                       }
+                       else if ( strcmp(arg, "-warn_stabs") == 0 ) {
+                               fWarnStabs = true;
+                       }
+                       else if ( strcmp(arg, "-pause") == 0 ) {
+                               fPause = true;
+                       }
+                       else if ( strcmp(arg, "-print_statistics") == 0 ) {
+                               fStatistics = true;
+                       }
                        else if ( strcmp(arg, "-v") == 0 ) {
                                // previously handled by buildSearchPaths()
                        }
@@ -1030,8 +1302,15 @@ void Options::parse(int argc, const char* argv[])
                                ++i;
                                // previously handled by buildSearchPaths()
                        }
+                       else if ( strcmp(arg, "-no_uuid") == 0 ) {
+                               fEmitUUID = false;
+                       }
+                       // put this last so that it does not interfer with other options starting with 'i'
+                       else if ( strncmp(arg, "-i", 2) == 0 ) {
+                               fprintf(stderr, "ld64: -i option (indirect symbols) not supported\n");
+                       }
                        else {
-                               fprintf(stderr, "unknown option: %s\n", arg);
+                               throwf("unknown option: %s", arg);
                        }
                }
                else {
@@ -1040,22 +1319,22 @@ void Options::parse(int argc, const char* argv[])
        }
 }
 
-
-
-// 
-// -syslibroot <path> is used for SDK support.  
+//
+// -syslibroot <path> is used for SDK support.
 // The rule is that all search paths (both explicit and default) are
 // checked to see if they exist in the SDK.  If so, that path is
 // replaced with the sdk prefixed path.  If not, that search path
 // is used as is.  If multiple -syslibroot options are specified
 // their directory structures are logically overlayed and files
 // from sdks specified earlier on the command line used before later ones.
-// 
+
 void Options::buildSearchPaths(int argc, const char* argv[])
 {
        bool addStandardLibraryDirectories = true;
        std::vector<const char*> libraryPaths;
        std::vector<const char*> frameworkPaths;
+       libraryPaths.reserve(10);
+       frameworkPaths.reserve(10);
        // scan through argv looking for -L, -F, -Z, and -syslibroot options
        for(int i=0; i < argc; ++i) {
                if ( (argv[i][0] == '-') && (argv[i][1] == 'L') )
@@ -1082,13 +1361,14 @@ void Options::buildSearchPaths(int argc, const char* argv[])
        if ( addStandardLibraryDirectories ) {
                libraryPaths.push_back("/usr/lib");
                libraryPaths.push_back("/usr/local/lib");
-               
+
                frameworkPaths.push_back("/Library/Frameworks/");
                frameworkPaths.push_back("/Network/Library/Frameworks/");
                frameworkPaths.push_back("/System/Library/Frameworks/");
        }
-       
+
        // now merge sdk and library paths to make real search paths
+       fLibrarySearchPaths.reserve(libraryPaths.size()*(fSDKPaths.size()+1));
        for (std::vector<const char*>::iterator it = libraryPaths.begin(); it != libraryPaths.end(); it++) {
                const char* libDir = *it;
                bool sdkOverride = false;
@@ -1096,10 +1376,11 @@ void Options::buildSearchPaths(int argc, const char* argv[])
                        char betterLibDir[PATH_MAX];
                        if ( strstr(libDir, "/..") != NULL ) {
                                if ( realpath(libDir, betterLibDir) != NULL )
-                                       libDir = betterLibDir;
+                                       libDir = strdup(betterLibDir);
                        }
                        const int libDirLen = strlen(libDir);
                        for (std::vector<const char*>::iterator sdkit = fSDKPaths.begin(); sdkit != fSDKPaths.end(); sdkit++) {
+                               // ??? Should be using string here.
                                const char* sdkDir = *sdkit;
                                const int sdkDirLen = strlen(sdkDir);
                                char newPath[libDirLen + sdkDirLen+4];
@@ -1114,11 +1395,12 @@ void Options::buildSearchPaths(int argc, const char* argv[])
                                }
                        }
                }
-               if ( !sdkOverride ) 
+               if ( !sdkOverride )
                        fLibrarySearchPaths.push_back(libDir);
        }
-       
+
        // now merge sdk and framework paths to make real search paths
+       fFrameworkSearchPaths.reserve(frameworkPaths.size()*(fSDKPaths.size()+1));
        for (std::vector<const char*>::iterator it = frameworkPaths.begin(); it != frameworkPaths.end(); it++) {
                const char* frameworkDir = *it;
                bool sdkOverride = false;
@@ -1126,10 +1408,11 @@ void Options::buildSearchPaths(int argc, const char* argv[])
                        char betterFrameworkDir[PATH_MAX];
                        if ( strstr(frameworkDir, "/..") != NULL ) {
                                if ( realpath(frameworkDir, betterFrameworkDir) != NULL )
-                                       frameworkDir = betterFrameworkDir;
+                                       frameworkDir = strdup(betterFrameworkDir);
                        }
                        const int frameworkDirLen = strlen(frameworkDir);
                        for (std::vector<const char*>::iterator sdkit = fSDKPaths.begin(); sdkit != fSDKPaths.end(); sdkit++) {
+                               // ??? Should be using string here
                                const char* sdkDir = *sdkit;
                                const int sdkDirLen = strlen(sdkDir);
                                char newPath[frameworkDirLen + sdkDirLen+4];
@@ -1144,16 +1427,20 @@ void Options::buildSearchPaths(int argc, const char* argv[])
                                }
                        }
                }
-               if ( !sdkOverride ) 
+               if ( !sdkOverride )
                        fFrameworkSearchPaths.push_back(frameworkDir);
        }
-       
+
        if ( fVerbose ) {
                fprintf(stderr,"Library search paths:\n");
-               for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin(); it != fLibrarySearchPaths.end(); it++)
+               for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin();
+                        it != fLibrarySearchPaths.end();
+                        it++)
                        fprintf(stderr,"\t%s\n", *it);
                fprintf(stderr,"Framework search paths:\n");
-               for (std::vector<const char*>::iterator it = fFrameworkSearchPaths.begin(); it != fFrameworkSearchPaths.end(); it++)
+               for (std::vector<const char*>::iterator it = fFrameworkSearchPaths.begin();
+                        it != fFrameworkSearchPaths.end();
+                        it++)
                        fprintf(stderr,"\t%s\n", *it);
        }
 }
@@ -1161,19 +1448,34 @@ void Options::buildSearchPaths(int argc, const char* argv[])
 // this is run before the command line is parsed
 void Options::parsePreCommandLineEnvironmentSettings()
 {
-       if ( getenv("RC_TRACE_ARCHIVES") != NULL)
+       if ((getenv("LD_TRACE_ARCHIVES") != NULL)
+               || (getenv("RC_TRACE_ARCHIVES") != NULL))
            fReaderOptions.fTraceArchives = true;
-               
-       if ( getenv("RC_TRACE_DYLIBS") != NULL) {
+
+       if ((getenv("LD_TRACE_DYLIBS") != NULL)
+               || (getenv("RC_TRACE_DYLIBS") != NULL)) {
            fReaderOptions.fTraceDylibs = true;
                fReaderOptions.fTraceIndirectDylibs = true;
        }
+
+       if (getenv("RC_TRACE_DYLIB_SEARCHING") != NULL) {
+           fTraceDylibSearching = true;
+       }
+
+       if (getenv("LD_PRINT_OPTIONS") != NULL)
+               fPrintOptions = true;
+
+       if (fReaderOptions.fTraceDylibs || fReaderOptions.fTraceArchives)
+               fReaderOptions.fTraceOutputFile = getenv("LD_TRACE_FILE");
 }
 
 // this is run after the command line is parsed
 void Options::parsePostCommandLineEnvironmentSettings()
 {
-
+       // when building a dynamic main executable, default any use of @executable_path to output path
+       if ( fExecutablePath == NULL && (fOutputKind == kDynamicExecutable) ) {
+               fExecutablePath = fOutputFile;
+       }
 }
 
 void Options::checkIllegalOptionCombinations()
@@ -1191,7 +1493,7 @@ void Options::checkIllegalOptionCombinations()
                                throw "can't use -undefined warning or suppress with -twolevel_namespace";
                        break;
        }
-       
+
        // unify -sub_umbrella with dylibs
        for (std::vector<const char*>::iterator it = fSubUmbellas.begin(); it != fSubUmbellas.end(); it++) {
                const char* subUmbrella = *it;
@@ -1210,7 +1512,7 @@ void Options::checkIllegalOptionCombinations()
                if ( ! found )
                        fprintf(stderr, "ld64 warning: -sub_umbrella %s does not match a supplied dylib\n", subUmbrella);
        }
-       
+
        // unify -sub_library with dylibs
        for (std::vector<const char*>::iterator it = fSubLibraries.begin(); it != fSubLibraries.end(); it++) {
                const char* subLibrary = *it;
@@ -1232,17 +1534,17 @@ void Options::checkIllegalOptionCombinations()
                if ( ! found )
                        fprintf(stderr, "ld64 warning: -sub_library %s does not match a supplied dylib\n", subLibrary);
        }
-       
+
        // sync reader options
        if ( fNameSpace != kTwoLevelNameSpace )
                fReaderOptions.fFlatNamespace = true;
 
        // check -stack_addr
-       if ( fStackAddr != 0 ) { 
+       if ( fStackAddr != 0 ) {
                switch (fArchitecture) {
                        case CPU_TYPE_I386:
                        case CPU_TYPE_POWERPC:
-                               if ( fStackAddr > 0xFFFFFFFF ) 
+                               if ( fStackAddr > 0xFFFFFFFF )
                                        throw "-stack_addr must be < 4G for 32-bit processes";
                                break;
                        case CPU_TYPE_POWERPC64:
@@ -1253,13 +1555,13 @@ void Options::checkIllegalOptionCombinations()
                if ( fStackSize  == 0 )
                        throw "-stack_addr must be used with -stack_size";
        }
-       
+
        // check -stack_size
-       if ( fStackSize != 0 ) { 
+       if ( fStackSize != 0 ) {
                switch (fArchitecture) {
                        case CPU_TYPE_I386:
                        case CPU_TYPE_POWERPC:
-                               if ( fStackSize > 0xFFFFFFFF ) 
+                               if ( fStackSize > 0xFFFFFFFF )
                                        throw "-stack_size must be < 4G for 32-bit processes";
                                if ( fStackAddr == 0 ) {
                                        fprintf(stderr, "ld64 warning: -stack_addr not specified, using the default 0xC0000000\n");
@@ -1278,7 +1580,7 @@ void Options::checkIllegalOptionCombinations()
                switch ( fOutputKind ) {
                        case Options::kDynamicExecutable:
                        case Options::kStaticExecutable:
-                               // custom stack size only legeal when building main executable
+                               // custom stack size only legal when building main executable
                                break;
                        case Options::kDynamicLibrary:
                        case Options::kDynamicBundle:
@@ -1287,15 +1589,36 @@ void Options::checkIllegalOptionCombinations()
                                throw "-stack_size option can only be used when linking a main executable";
                }
        }
-       
+
+       // check that -allow_stack_execute is only used with main executables
+       if ( fExecutableStack ) {
+               switch ( fOutputKind ) {
+                       case Options::kDynamicExecutable:
+                       case Options::kStaticExecutable:
+                               // -allow_stack_execute size only legal when building main executable
+                               break;
+                       case Options::kDynamicLibrary:
+                       case Options::kDynamicBundle:
+                       case Options::kObjectFile:
+                       case Options::kDyld:
+                               throw "-allow_stack_execute option can only be used when linking a main executable";
+               }
+       }
+
+       // check -client_name is only used when -bundle is specified
+       if ( (fClientName != NULL) && (fOutputKind != Options::kDynamicBundle) )
+               throw "-client_name can only be used with -bundle";
+
        // check -init is only used when building a dylib
        if ( (fInitFunctionName != NULL) && (fOutputKind != Options::kDynamicLibrary) )
                throw "-init can only be used with -dynamiclib";
-               
-       // make sure all required exported symbols exist
-       for (NameSet::iterator it=fExportSymbols.begin(); it != fExportSymbols.end(); it++)
-               fInitialUndefines.push_back(*it);
-               
-}
 
+       // make sure all required exported symbols exist
+       for (NameSet::iterator it=fExportSymbols.begin(); it != fExportSymbols.end(); it++) {
+               const char* name = *it;
+               // never export .eh symbols
+               if ( strcmp(&name[strlen(name)-3], ".eh") != 0 )
+                       fInitialUndefines.push_back(name);
+       }
 
+}
diff --git a/src/Options.cpp.orig b/src/Options.cpp.orig
deleted file mode 100644 (file)
index 6984e67..0000000
+++ /dev/null
@@ -1,1297 +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@
- */
-
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <vector>
-
-
-#include "Options.h"
-
- __attribute__((noreturn))
-void throwf(const char* format, ...) 
-{
-       va_list list;
-       char*   p;
-       va_start(list, format);
-       vasprintf(&p, format, list);
-       va_end(list);
-       
-       const char*     t = p;
-       throw t;
-}
-
-
-Options::Options(int argc, const char* argv[])
- : fOutputFile("a.out"), fArchitecture(CPU_TYPE_POWERPC64), fOutputKind(kDynamicExecutable), fBindAtLoad(false),
-       fStripLocalSymbols(false),  fKeepPrivateExterns(false),
-       fInterposable(false), fIgnoreOtherArchFiles(false), fForceSubtypeAll(false), fNameSpace(kTwoLevelNameSpace),
-       fDylibCompatVersion(0), fDylibCurrentVersion(0), fDylibInstallName(NULL), fEntryName("start"), fBaseAddress(0),
-       fExportMode(kExportDefault), fLibrarySearchMode(kSearchAllDirsForDylibsThenAllDirsForArchives),
-       fUndefinedTreatment(kUndefinedError), fMessagesPrefixedWithArchitecture(false), fPICTreatment(kPICError),
-       fWeakReferenceMismatchTreatment(kWeakReferenceMismatchError), 
-       fUmbrellaName(NULL), fInitFunctionName(NULL), fZeroPageSize(0x1000), fStackSize(0), fStackAddr(0), fMinimumHeaderPad(0),
-       fCommonsMode(kCommonsIgnoreDylibs), fWarnCommons(false), fVerbose(false)
-{
-       this->parsePreCommandLineEnvironmentSettings();
-       this->parse(argc, argv);
-       this->parsePostCommandLineEnvironmentSettings();
-       this->checkIllegalOptionCombinations();
-}
-
-Options::~Options()
-{
-}
-
-
-ObjectFile::ReaderOptions& Options::readerOptions()
-{
-       return fReaderOptions;
-}
-
-cpu_type_t Options::architecture()
-{
-       return fArchitecture;
-}
-
-
-const char*    Options::getOutputFilePath()
-{
-       return fOutputFile;
-}
-
-
-std::vector<Options::FileInfo>& Options::getInputFiles()
-{
-       return fInputFiles;
-}
-
-Options::OutputKind    Options::outputKind()
-{
-       return fOutputKind;
-}
-
-bool Options::stripLocalSymbols()
-{
-       return fStripLocalSymbols;
-}
-
-bool Options::stripDebugInfo()
-{
-       return fReaderOptions.fStripDebugInfo;
-}
-
-bool Options::bindAtLoad()
-{
-       return fBindAtLoad;
-}
-
-bool Options::fullyLoadArchives()
-{
-       return fReaderOptions.fFullyLoadArchives;
-}
-
-Options::NameSpace Options::nameSpace()
-{
-       return fNameSpace;
-}
-
-const char*    Options::installPath()
-{
-       if ( fDylibInstallName != NULL ) 
-               return fDylibInstallName;
-       else
-               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()
-{
-       return fInterposable;
-}
-
-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;
-}
-
-uint64_t Options::zeroPageSize()
-{
-       return fZeroPageSize;
-}
-
-bool Options::hasCustomStack()
-{
-       return (fStackSize != 0);
-}
-       
-uint64_t Options::customStackSize()
-{
-       return fStackSize;
-}
-
-uint64_t Options::customStackAddr()
-{
-       return fStackAddr;
-}
-
-std::vector<const char*>& Options::initialUndefines()
-{
-       return fInitialUndefines;
-}
-
-const char*    Options::initFunctionName()
-{
-       return fInitFunctionName;
-}
-
-bool Options::hasExportRestrictList()
-{
-       return (fExportMode != kExportDefault);
-}
-
-uint32_t Options::minimumHeaderPad()
-{
-       return fMinimumHeaderPad;
-}
-
-std::vector<Options::ExtraSection>&    Options::extraSections()
-{
-       return fExtraSections;
-}
-
-std::vector<Options::SectionAlignment>&        Options::sectionAlignments()
-{
-       return fSectionAlignments;
-}
-
-
-Options::CommonsMode Options::commonsMode()
-{
-       return fCommonsMode;
-}
-
-bool Options::warnCommons()
-{
-       return fWarnCommons;
-}
-
-bool Options::shouldExport(const char* symbolName)
-{
-       switch (fExportMode) {
-               case kExportSome:
-                       return ( fExportSymbols.find(symbolName) != fExportSymbols.end() );
-               case kDontExportSome:
-                       return ( fDontExportSymbols.find(symbolName) == fDontExportSymbols.end() );
-               case kExportDefault:
-                       return true;
-       }
-       throw "internal error";
-}
-
-
-void Options::parseArch(const char* architecture)
-{
-       if ( architecture == NULL )
-               throw "-arch must be followed by an architecture string";
-       if ( strcmp(architecture, "ppc") == 0 )
-               fArchitecture = CPU_TYPE_POWERPC;
-       else if ( strcmp(architecture, "ppc64") == 0 )
-               fArchitecture = CPU_TYPE_POWERPC64;
-       else if ( strcmp(architecture, "i386") == 0 )
-               fArchitecture = CPU_TYPE_I386;
-       else 
-               throw "-arch followed by unknown architecture name";
-}
-
-bool Options::checkForFile(const char* format, const char* dir, const char* rootName, FileInfo& result)
-{
-       struct stat statBuffer;
-       char possiblePath[strlen(dir)+strlen(rootName)+20];
-       sprintf(possiblePath, format,  dir, rootName);
-       if ( stat(possiblePath, &statBuffer) == 0 ) {
-               result.path = strdup(possiblePath);
-               result.fileLen = statBuffer.st_size;
-               return true;
-       }
-       return false;
-} 
-
-
-Options::FileInfo Options::findLibrary(const char* rootName)
-{
-       FileInfo result;
-       const int rootNameLen = strlen(rootName);
-       // if rootName ends in .o there is no .a vs .dylib choice
-       if ( (rootNameLen > 3) && (strcmp(&rootName[rootNameLen-2], ".o") == 0) ) {
-               for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin(); it != fLibrarySearchPaths.end(); it++) {
-                       const char* dir = *it;
-                       if ( checkForFile("%s/%s", dir, rootName, result) )
-                               return result;
-               }
-       }
-       else {
-               bool lookForDylibs = ( fOutputKind != Options::kDyld);
-               switch ( fLibrarySearchMode ) {
-                       case kSearchAllDirsForDylibsThenAllDirsForArchives:
-                               // first look in all directories for just for dylibs
-                               if ( lookForDylibs ) {
-                                       for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin(); it != fLibrarySearchPaths.end(); it++) {
-                                               const char* dir = *it;
-                                               if ( checkForFile("%s/lib%s.dylib", dir, rootName, result) )
-                                                       return result;
-                                       }
-                               }
-                               // next look in all directories for just for archives
-                               for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin(); it != fLibrarySearchPaths.end(); it++) {
-                                       const char* dir = *it;
-                                       if ( checkForFile("%s/lib%s.a", dir, rootName, result) )
-                                               return result;
-                               }
-                               break;
-
-                       case kSearchDylibAndArchiveInEachDir:
-                               // look in each directory for just for a dylib then for an archive
-                               for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin(); it != fLibrarySearchPaths.end(); it++) {
-                                       const char* dir = *it;
-                                       if ( lookForDylibs && checkForFile("%s/lib%s.dylib", dir, rootName, result) )
-                                               return result;
-                                       if ( checkForFile("%s/lib%s.a", dir, rootName, result) )
-                                               return result;
-                               }
-                               break;
-               }
-       }
-       throwf("library not found for -l%s", rootName);
-}
-
-
-Options::FileInfo Options::findFramework(const char* rootName)
-{
-       struct stat statBuffer;
-       const int rootNameLen = strlen(rootName);
-       for (std::vector<const char*>::iterator it = fFrameworkSearchPaths.begin(); it != fFrameworkSearchPaths.end(); it++) {
-               const char* dir = *it;
-               char possiblePath[strlen(dir)+2*rootNameLen+20];
-               strcpy(possiblePath, dir);
-               strcat(possiblePath, "/");
-               strcat(possiblePath, rootName);
-               strcat(possiblePath, ".framework/");
-               strcat(possiblePath, rootName);
-               if ( stat(possiblePath, &statBuffer) == 0 ) {
-                       FileInfo result;
-                       result.path = strdup(possiblePath);
-                       result.fileLen = statBuffer.st_size;
-                       return result;
-               }
-       }
-       throwf("framework not found %s", rootName);
-}
-
-Options::FileInfo Options::findFile(const char* path)
-{
-       FileInfo result;
-       struct stat statBuffer;
-       
-       // if absolute path and not a .o file, the use SDK prefix
-       if ( (path[0] == '/') && (strcmp(&path[strlen(path)-2], ".o") != 0) ) {
-               const int pathLen = strlen(path);
-               for (std::vector<const char*>::iterator it = fSDKPaths.begin(); it != fSDKPaths.end(); it++) {
-                       const char* sdkPathDir = *it;
-                       const int sdkPathDirLen = strlen(sdkPathDir);
-                       char possiblePath[sdkPathDirLen+pathLen+4];
-                       strcpy(possiblePath, sdkPathDir);
-                       if ( possiblePath[sdkPathDirLen-1] == '/' )
-                               possiblePath[sdkPathDirLen-1] = '\0';
-                       strcat(possiblePath, path);
-                       if ( stat(possiblePath, &statBuffer) == 0 ) {
-                               result.path = strdup(possiblePath);
-                               result.fileLen = statBuffer.st_size;
-                               return result;
-                       }
-               }
-       }
-       // try raw path
-       if ( stat(path, &statBuffer) == 0 ) {
-               result.path = strdup(path);
-               result.fileLen = statBuffer.st_size;
-               return result;
-       }
-       // not found
-       throwf("file not found: %s", path);
-}
-
-
-void Options::loadFileList(const char* fileOfPaths)
-{
-       FILE* file = fopen(fileOfPaths, "r");
-       if ( file == NULL ) 
-               throwf("-filelist file not found: %s\n", fileOfPaths);
-       
-       char path[1024];
-       while ( fgets(path, 1024, file) != NULL ) {
-               path[1023] = '\0';
-               char* eol = strchr(path, '\n');
-               if ( eol != NULL )
-                       *eol = '\0';
-                       
-               fInputFiles.push_back(findFile(path));
-       }
-       fclose(file);
-}
-
-
-void Options::loadExportFile(const char* fileOfExports, const char* option, NameSet& set)
-{
-       // read in whole file
-       int fd = ::open(fileOfExports, O_RDONLY, 0);
-       if ( fd == -1 )
-               throwf("can't open %s file: %s", option, fileOfExports);
-       struct stat stat_buf;
-       ::fstat(fd, &stat_buf);
-       char* p = (char*)malloc(stat_buf.st_size);
-       if ( p == NULL )
-               throwf("can't process %s file: %s", option, fileOfExports);
-       
-       if ( read(fd, p, stat_buf.st_size) != stat_buf.st_size )
-               throwf("can't read %s file: %s", option, fileOfExports);
-       
-       ::close(fd);
-       
-       // parse into symbols and add to hash_set
-       char * const end = &p[stat_buf.st_size];
-       enum { lineStart, inSymbol, inComment } state = lineStart;
-       char* symbolStart = NULL;
-       for (char* s = p; s < end; ++s ) {
-               switch ( state ) {
-                       case lineStart:
-                               if ( *s =='#' ) {
-                                       state = inComment;
-                               }
-                               else if ( !isspace(*s) ) {
-                                       state = inSymbol;
-                                       symbolStart = s;
-                               }
-                               break;
-                       case inSymbol:
-                               if ( *s == '\n' ) {
-                                       *s = '\0';
-                                       // removing any trailing spaces
-                                       char* last = s-1;
-                                       while ( isspace(*last) ) {
-                                               *last = '\0';
-                                               --last;
-                                       }
-                                       set.insert(symbolStart);
-                                       symbolStart = NULL;
-                                       state = lineStart;
-                               }
-                               break;
-                       case inComment:
-                               if ( *s == '\n' )
-                                       state = lineStart;
-                               break;
-               }
-       }
-       // Note: we do not free() the malloc buffer, because the strings are used by the export-set hash table
-}
-
-void Options::setUndefinedTreatment(const char* treatment)
-{
-       if ( treatment == NULL ) 
-               throw "-undefined missing [ warning | error | suppress | dynamic_lookup ]";
-
-       if ( strcmp(treatment, "warning") == 0 )
-               fUndefinedTreatment = kUndefinedWarning;
-       else if ( strcmp(treatment, "error") == 0 )
-               fUndefinedTreatment = kUndefinedError;
-       else if ( strcmp(treatment, "suppress") == 0 )
-               fUndefinedTreatment = kUndefinedSuppress;
-       else if ( strcmp(treatment, "dynamic_lookup") == 0 )
-               fUndefinedTreatment = kUndefinedDynamicLookup;
-       else
-               throw "invalid option to -undefined [ warning | error | suppress | dynamic_lookup ]";
-}
-
-void Options::setReadOnlyRelocTreatment(const char* treatment)
-{
-       if ( treatment == NULL ) 
-               throw "-read_only_relocs missing [ warning | error | suppress ]";
-
-       if ( strcmp(treatment, "warning") == 0 )
-               throw "-read_only_relocs warning not supported";
-       else if ( strcmp(treatment, "suppress") == 0 )
-               throw "-read_only_relocs suppress not supported";
-       else if ( strcmp(treatment, "error") != 0 )
-               throw "invalid option to -read_only_relocs [ warning | error | suppress | dynamic_lookup ]";
-}
-
-void Options::setPICTreatment(const char* treatment)
-{
-       if ( treatment == NULL ) 
-               throw "-sect_diff_relocs missing [ warning | error | suppress ]";
-
-       if ( strcmp(treatment, "warning") == 0 )
-               fPICTreatment = kPICWarning;
-       else if ( strcmp(treatment, "error") == 0 )
-               fPICTreatment = kPICError;
-       else if ( strcmp(treatment, "suppress") == 0 )
-               fPICTreatment = kPICSuppress;
-       else
-               throw "invalid option to -sect_diff_relocs [ warning | error | suppress ]";
-}
-
-void Options::setWeakReferenceMismatchTreatment(const char* treatment)
-{
-       if ( treatment == NULL ) 
-               throw "-weak_reference_mismatches missing [ error | weak | non-weak ]";
-
-       if ( strcmp(treatment, "error") == 0 )
-               fWeakReferenceMismatchTreatment = kWeakReferenceMismatchError;
-       else if ( strcmp(treatment, "weak") == 0 )
-               fWeakReferenceMismatchTreatment = kWeakReferenceMismatchWeak;
-       else if ( strcmp(treatment, "non-weak") == 0 )
-               fWeakReferenceMismatchTreatment = kWeakReferenceMismatchNonWeak;
-       else
-               throw "invalid option to -weak_reference_mismatches [ error | weak | non-weak ]";
-}
-
-Options::CommonsMode Options::parseCommonsTreatment(const char* mode)
-{
-       if ( mode == NULL ) 
-               throw "-commons missing [ ignore_dylibs | use_dylibs | error ]";
-
-       if ( strcmp(mode, "ignore_dylibs") == 0 )
-               return kCommonsIgnoreDylibs;
-       else if ( strcmp(mode, "use_dylibs") == 0 )
-               return kCommonsOverriddenByDylibs;
-       else if ( strcmp(mode, "error") == 0 )
-               return kCommonsConflictsDylibsError;
-       else
-               throw "invalid option to -commons [ ignore_dylibs | use_dylibs | error ]";
-}
-
-
-void Options::setDylibInstallNameOverride(const char* paths)
-{
-
-
-}
-
-void Options::setExecutablePath(const char* path)
-{
-
-
-}
-
-
-
-
-uint64_t Options::parseAddress(const char* addr)
-{
-       char* endptr;
-       uint64_t result = strtoull(addr, &endptr, 16);
-       return result;
-}
-
-
-
-//
-// Parses number of form X[.Y[.Z]] into a uint32_t where the nibbles are xxxx.yy.zz 
-//
-//
-uint32_t Options::parseVersionNumber(const char* versionString)
-{
-       unsigned long x = 0;
-       unsigned long y = 0;
-       unsigned long z = 0;
-       char* end;
-       x = strtoul(versionString, &end, 10);
-       if ( *end == '.' ) {
-               y = strtoul(&end[1], &end, 10);
-               if ( *end == '.' ) {
-                       z = strtoul(&end[1], &end, 10);
-               }
-       }
-       if ( (*end != '\0') || (x > 0xffff) || (y > 0xff) || (z > 0xff) )
-               throwf("malformed version number: %s", versionString);
-
-       return (x << 16) | ( y << 8 ) | z;
-}
-
-void Options::parseSectionOrderFile(const char* segment, const char* section, const char* path)
-{
-       fprintf(stderr, "ld64: warning -sectorder not yet supported for 64-bit code\n");
-}
-
-void Options::addSection(const char* segment, const char* section, const char* path)
-{
-       if ( strlen(segment) > 16 )
-               throw "-seccreate segment name max 16 chars";
-       if ( strlen(section) > 16 )
-               throw "-seccreate section name max 16 chars";
-
-       // read in whole file
-       int fd = ::open(path, O_RDONLY, 0);
-       if ( fd == -1 )
-               throwf("can't open -sectcreate file: %s", path);
-       struct stat stat_buf;
-       ::fstat(fd, &stat_buf);
-       char* p = (char*)malloc(stat_buf.st_size);
-       if ( p == NULL )
-               throwf("can't process -sectcreate file: %s", path);
-       if ( read(fd, p, stat_buf.st_size) != stat_buf.st_size )
-               throwf("can't read -sectcreate file: %s", path);
-       ::close(fd);
-       
-       // record section to create
-       ExtraSection info = { segment, section, path, (uint8_t*)p, stat_buf.st_size };
-       fExtraSections.push_back(info);
-}
-
-void Options::addSectionAlignment(const char* segment, const char* section, const char* alignmentStr)
-{
-       if ( strlen(segment) > 16 )
-               throw "-sectalign segment name max 16 chars";
-       if ( strlen(section) > 16 )
-               throw "-sectalign section name max 16 chars";
-
-       char* endptr;
-       unsigned long value = strtoul(alignmentStr, &endptr, 16);
-       if ( *endptr != '\0')
-               throw "argument for -sectalign is not a hexadecimal number";
-       if ( value > 0x8000 )
-               throw "argument for -sectalign must be less than or equal to 0x8000";
-       uint8_t alignment = 0;
-       for(unsigned long x=value; x != 1; x >>= 1)
-               ++alignment;
-       if ( (unsigned long)(1 << alignment) != value )
-               throw "argument for -sectalign is not a power of two";
-
-       SectionAlignment info = { segment, section, alignment };
-       fSectionAlignments.push_back(info);
-}
-
-
-void Options::parse(int argc, const char* argv[])
-{
-       // pass one builds search list from -L and -F options
-       this->buildSearchPaths(argc, argv);
-       
-       // pass two parse all other options
-       for(int i=1; i < argc; ++i) {
-               const char* arg = argv[i];
-               
-               if ( arg[0] == '-' ) {
-                       if ( (arg[1] == 'L') || (arg[1] == 'F') ) {
-                               // previously handled by buildSearchPaths()
-                       }
-                       else if ( strcmp(arg, "-arch") == 0 ) {
-                               parseArch(argv[++i]);
-                       }
-                       else if ( strcmp(arg, "-dynamic") == 0 ) {
-                               // default
-                       }
-                       else if ( strcmp(arg, "-static") == 0 ) {
-                               fOutputKind = kStaticExecutable;
-                       }
-                       else if ( strcmp(arg, "-dylib") == 0 ) {
-                               fOutputKind = kDynamicLibrary;
-                       }
-                       else if ( strcmp(arg, "-bundle") == 0 ) {
-                               fOutputKind = kDynamicBundle;
-                       }
-                       else if ( strcmp(arg, "-dylinker") == 0 ) {
-                               fOutputKind = kDyld;
-                       }
-                       else if ( strcmp(arg, "-execute") == 0 ) {
-                               if ( fOutputKind != kStaticExecutable )
-                                       fOutputKind = kDynamicExecutable;
-                       }
-                       else if ( strcmp(arg, "-r") == 0 ) {
-                               fOutputKind = kObjectFile;
-                       }
-                       else if ( strcmp(arg, "-o") == 0 ) {
-                               fOutputFile = argv[++i];
-                       }
-                       else if ( arg[1] == 'l' ) {
-                               fInputFiles.push_back(findLibrary(&arg[2]));
-                       }
-                       else if ( strcmp(arg, "-weak-l") == 0 ) {
-                               FileInfo info = findLibrary(&arg[2]);
-                               info.options.fWeakImport = true;
-                               fInputFiles.push_back(info);
-                       }
-                       else if ( strcmp(arg, "-bind_at_load") == 0 ) {
-                               fBindAtLoad = true;
-                       }
-                       else if ( strcmp(arg, "-twolevel_namespace") == 0 ) {
-                               fNameSpace = kTwoLevelNameSpace;
-                       }
-                       else if ( strcmp(arg, "-flat_namespace") == 0 ) {
-                               fNameSpace = kFlatNameSpace;
-                       }
-                       else if ( strcmp(arg, "-force_flat_namespace") == 0 ) {
-                               fNameSpace = kForceFlatNameSpace;
-                       }
-                       else if ( strcmp(arg, "-all_load") == 0 ) {
-                               fReaderOptions.fFullyLoadArchives = true;
-                       }
-                       else if ( strcmp(arg, "-ObjC") == 0 ) {
-                               fReaderOptions.fLoadObjcClassesInArchives = true;
-                       }
-                       else if ( strcmp(arg, "-dylib_compatibility_version") == 0 ) {
-                               fDylibCompatVersion = parseVersionNumber(argv[++i]);
-                       }
-                       else if ( strcmp(arg, "-dylib_current_version") == 0 ) {
-                               fDylibCurrentVersion = parseVersionNumber(argv[++i]);
-                       }
-                       else if ( strcmp(arg, "-sectorder") == 0 ) {
-                               parseSectionOrderFile(argv[i+1], argv[i+2], argv[i+3]);
-                               i += 3;
-                       }
-                       else if ( (strcmp(arg, "-sectcreate") == 0) || (strcmp(arg, "-segcreate") == 0) ) {
-                               addSection(argv[i+1], argv[i+2], argv[i+3]);
-                               i += 3;
-                       }
-                       else if ( (strcmp(arg, "-dylib_install_name") == 0) || (strcmp(arg, "-dylinker_install_name") == 0) ) {
-                               fDylibInstallName = argv[++i];
-                       }
-                       else if ( strcmp(arg, "-seg1addr") == 0 ) {
-                               fBaseAddress = parseAddress(argv[++i]);
-                       }
-                       else if ( strcmp(arg, "-e") == 0 ) {
-                               fEntryName = argv[++i];
-                       }
-                       else if ( strcmp(arg, "-filelist") == 0 ) {
-                                loadFileList(argv[++i]);
-                       }
-                       else if ( strcmp(arg, "-keep_private_externs") == 0 ) {
-                                fKeepPrivateExterns = true;
-                       }
-                       else if ( strcmp(arg, "-final_output") == 0 ) {
-                                ++i;
-                               // ignore for now
-                       }
-                       else if ( (strcmp(arg, "-interposable") == 0) || (strcmp(arg, "-multi_module") == 0)) {
-                                fInterposable = true;
-                       }
-                       else if ( strcmp(arg, "-single_module") == 0 ) {
-                                fInterposable = false;
-                       }
-                       else if ( strcmp(arg, "-exported_symbols_list") == 0 ) {
-                               if ( fExportMode == kDontExportSome )
-                                       throw "can't use -exported_symbols_list and -unexported_symbols_list";
-                               fExportMode = kExportSome;
-                               loadExportFile(argv[++i], "-exported_symbols_list", fExportSymbols);
-                       }
-                       else if ( strcmp(arg, "-unexported_symbols_list") == 0 ) {
-                               if ( fExportMode == kExportSome )
-                                       throw "can't use -exported_symbols_list and -unexported_symbols_list";
-                               fExportMode = kDontExportSome;
-                               loadExportFile(argv[++i], "-unexported_symbols_list", fDontExportSymbols);
-                       }
-                       else if ( strcmp(arg, "-no_arch_warnings") == 0 ) {
-                                fIgnoreOtherArchFiles = true;
-                       }
-                       else if ( strcmp(arg, "-force_cpusubtype_ALL") == 0 ) {
-                                fForceSubtypeAll = true;
-                       }
-                       else if ( strcmp(arg, "-weak_library") == 0 ) {
-                               FileInfo info = findFile(argv[++i]);
-                               info.options.fWeakImport = true;
-                               fInputFiles.push_back(info);
-                       }
-                       else if ( strcmp(arg, "-framework") == 0 ) {
-                               fInputFiles.push_back(findFramework(argv[++i]));
-                       }
-                       else if ( strcmp(arg, "-weak_framework") == 0 ) {
-                               FileInfo info = findFramework(argv[++i]);
-                               info.options.fWeakImport = true;
-                               fInputFiles.push_back(info);
-                       }
-                       else if ( strcmp(arg, "-search_paths_first") == 0 ) {
-                               fLibrarySearchMode = kSearchDylibAndArchiveInEachDir;
-                       }
-                       else if ( strcmp(arg, "-undefined") == 0 ) {
-                                setUndefinedTreatment(argv[++i]);
-                       }
-                       else if ( strcmp(arg, "-arch_multiple") == 0 ) {
-                                fMessagesPrefixedWithArchitecture = true;
-                       }
-                       else if ( strcmp(arg, "-read_only_relocs") == 0 ) {
-                                setReadOnlyRelocTreatment(argv[++i]);
-                       }
-                       else if ( strcmp(arg, "-sect_diff_relocs") == 0 ) {
-                                setPICTreatment(argv[++i]);
-                       }
-                       else if ( strcmp(arg, "-weak_reference_mismatches") == 0 ) {
-                                setWeakReferenceMismatchTreatment(argv[++i]);
-                       }
-                       else if ( strcmp(arg, "-prebind") == 0 ) {
-                                 // FIX FIX
-                       }
-                       else if ( strcmp(arg, "-noprebind") == 0 ) {
-                                 // FIX FIX
-                       }
-                       else if ( strcmp(arg, "-prebind_allow_overlap") == 0 ) {
-                                 // FIX FIX
-                       }
-                       else if ( strcmp(arg, "-prebind_all_twolevel_modules") == 0 ) {
-                                 // FIX FIX
-                       }
-                       else if ( strcmp(arg, "-noprebind_all_twolevel_modules") == 0 ) {
-                                 // FIX FIX
-                       }
-                       else if ( strcmp(arg, "-nofixprebinding") == 0 ) {
-                                 // FIX FIX
-                       }
-                       else if ( strcmp(arg, "-dylib_file") == 0 ) {
-                                setDylibInstallNameOverride(argv[++i]);
-                       }
-                       else if ( strcmp(arg, "-executable_path") == 0 ) {
-                                setExecutablePath(argv[++i]);
-                       }
-                       else if ( strcmp(arg, "-segalign") == 0 ) {
-                               // FIX FIX
-                               ++i; 
-                       }
-                       else if ( strcmp(arg, "-segaddr") == 0 ) {
-                               // FIX FIX
-                               i += 2; 
-                       }
-                       else if ( strcmp(arg, "-segs_read_only_addr") == 0 ) {
-                               // FIX FIX
-                               ++i; 
-                       }
-                       else if ( strcmp(arg, "-segs_read_write_addr") == 0 ) {
-                               // FIX FIX
-                               ++i; 
-                       }
-                       else if ( strcmp(arg, "-seg_addr_table") == 0 ) {
-                               // FIX FIX
-                               ++i; 
-                       }
-                       else if ( strcmp(arg, "-seg_addr_table_filename") == 0 ) {
-                               // FIX FIX
-                               ++i; 
-                       }
-                       else if ( strcmp(arg, "-segprot") == 0 ) {
-                               // FIX FIX
-                               i += 3; 
-                       }
-                       else if ( strcmp(arg, "-pagezero_size") == 0 ) {
-                               fZeroPageSize = parseAddress(argv[++i]);
-                               fZeroPageSize &= (-4096); // page align
-                       }
-                       else if ( strcmp(arg, "-stack_addr") == 0 ) {
-                               fStackAddr = parseAddress(argv[++i]);
-                       }
-                       else if ( strcmp(arg, "-stack_size") == 0 ) {
-                               fStackSize = parseAddress(argv[++i]);
-                       }
-                       else if ( strcmp(arg, "-sectalign") == 0 ) {
-                               addSectionAlignment(argv[i+1], argv[i+2], argv[i+3]);
-                               i += 3;
-                       }
-                       else if ( strcmp(arg, "-sectorder_detail") == 0 ) {
-                                // FIX FIX
-                       }
-                       else if ( strcmp(arg, "-sectobjectsymbols") == 0 ) {
-                               // FIX FIX
-                               i += 2;
-                       }
-                       else if ( strcmp(arg, "-bundle_loader") == 0 ) {
-                               // FIX FIX
-                               ++i;
-                       }
-                       else if ( strcmp(arg, "-private_bundle") == 0 ) {
-                               // FIX FIX
-                       }
-                       else if ( strcmp(arg, "-twolevel_namespace_hints") == 0 ) {
-                               // FIX FIX
-                       }
-                       else if ( strcmp(arg, "-multiply_defined") == 0 ) {
-                               // FIX FIX
-                               ++i;
-                       }
-                       else if ( strcmp(arg, "-multiply_defined_unused") == 0 ) {
-                               // FIX FIX
-                               ++i;
-                       }
-                       else if ( strcmp(arg, "-nomultidefs") == 0 ) {
-                                // FIX FIX
-                       }
-                       else if ( arg[1] == 'y' ) {
-                                // FIX FIX
-                       }
-                       else if ( strcmp(arg, "-Y") == 0 ) {
-                                ++i;
-                                // FIX FIX
-                       }
-                       else if ( strcmp(arg, "-m") == 0 ) {
-                                // FIX FIX
-                       }
-                       else if ( strcmp(arg, "-whyload") == 0 ) {
-                                // FIX FIX
-                       }
-                       else if ( strcmp(arg, "-u") == 0 ) {
-                               const char* name = argv[++i];
-                               if ( name == NULL )
-                                       throw "-u missing argument";
-                               fInitialUndefines.push_back(name);
-                       }
-                       else if ( strcmp(arg, "-i") == 0 ) {
-                                  // FIX FIX
-                       }
-                       else if ( strcmp(arg, "-U") == 0 ) {
-                                // FIX FIX
-                                ++i;  
-                       }
-                       else if ( strcmp(arg, "-s") == 0 ) {
-                               // FIX FIX
-                       }
-                       else if ( strcmp(arg, "-x") == 0 ) {
-                               // FIX FIX
-                       }
-                       else if ( strcmp(arg, "-S") == 0 ) {
-                               // FIX FIX
-                       }
-                       else if ( strcmp(arg, "-X") == 0 ) {
-                               // FIX FIX
-                       }
-                       else if ( strcmp(arg, "-Si") == 0 ) {
-                               // FIX FIX
-                       }
-                       else if ( strcmp(arg, "-b") == 0 ) {
-                               // FIX FIX
-                       }
-                       else if ( strcmp(arg, "-Sn") == 0 ) {
-                               // FIX FIX
-                       }
-                       else if ( strcmp(arg, "-dead_strip") == 0 ) {
-                                // FIX FIX
-                                fprintf(stderr, "ld64: warning -dead_strip not yet supported for 64-bit code\n");
-                       }
-                       else if ( strcmp(arg, "-w") == 0 ) {
-                               // FIX FIX
-                       }
-                       else if ( strcmp(arg, "-arch_errors_fatal") == 0 ) {
-                               // FIX FIX
-                       }
-                       else if ( strcmp(arg, "-M") == 0 ) {
-                               // FIX FIX
-                       }
-                       else if ( strcmp(arg, "-whatsloaded") == 0 ) {
-                               // FIX FIX
-                       }
-                       else if ( strcmp(arg, "-headerpad") == 0 ) {
-                               const char* size = argv[++i];
-                               if ( size == NULL )
-                                       throw "-headerpad missing argument";
-                                fMinimumHeaderPad = parseAddress(size);
-                       }
-                       else if ( strcmp(arg, "-headerpad_max_install_names") == 0 ) {
-                               // FIX FIX
-                       }
-                       else if ( strcmp(arg, "-t") == 0 ) {
-                               // FIX FIX
-                       }
-                       else if ( strcmp(arg, "-A") == 0 ) {
-                                // FIX FIX
-                                ++i;  
-                       }
-                       else if ( strcmp(arg, "-umbrella") == 0 ) {
-                               const char* name = argv[++i];
-                               if ( name == NULL )
-                                       throw "-umbrella missing argument";
-                               fUmbrellaName = name;
-                       }
-                       else if ( strcmp(arg, "-allowable_client") == 0 ) {
-                                // FIX FIX
-                                ++i;  
-                       }
-                       else if ( strcmp(arg, "-client_name") == 0 ) {
-                                // FIX FIX
-                                ++i;  
-                       }
-                       else if ( strcmp(arg, "-sub_umbrella") == 0 ) {
-                               const char* name = argv[++i];
-                               if ( name == NULL )
-                                       throw "-sub_umbrella missing argument";
-                                fSubUmbellas.push_back(name);
-                       }
-                       else if ( strcmp(arg, "-sub_library") == 0 ) {
-                               const char* name = argv[++i];
-                               if ( name == NULL )
-                                       throw "-sub_library missing argument";
-                                fSubLibraries.push_back(name);
-                       }
-                       else if ( strcmp(arg, "-init") == 0 ) {
-                               const char* name = argv[++i];
-                               if ( name == NULL )
-                                       throw "-init missing argument";
-                               fInitFunctionName = name;
-                       }
-                       else if ( strcmp(arg, "-warn_commons") == 0 ) {
-                               fWarnCommons = true;
-                       }
-                       else if ( strcmp(arg, "-commons") == 0 ) {
-                               fCommonsMode = parseCommonsTreatment(argv[++i]);
-                       }
-                       else if ( strcmp(arg, "-v") == 0 ) {
-                               // previously handled by buildSearchPaths()
-                       }
-                       else if ( strcmp(arg, "-Z") == 0 ) {
-                               // previously handled by buildSearchPaths()
-                       }
-                       else if ( strcmp(arg, "-syslibroot") == 0 ) {
-                               ++i;
-                               // previously handled by buildSearchPaths()
-                       }
-                       else {
-                               fprintf(stderr, "unknown option: %s\n", arg);
-                       }
-               }
-               else {
-                       fInputFiles.push_back(findFile(arg));
-               }
-       }
-}
-
-
-
-// 
-// -syslibroot <path> is used for SDK support.  
-// The rule is that all search paths (both explicit and default) are
-// checked to see if they exist in the SDK.  If so, that path is
-// replaced with the sdk prefixed path.  If not, that search path
-// is used as is.  If multiple -syslibroot options are specified
-// their directory structures are logically overlayed and files
-// from sdks specified earlier on the command line used before later ones.
-// 
-void Options::buildSearchPaths(int argc, const char* argv[])
-{
-       bool addStandardLibraryDirectories = true;
-       std::vector<const char*> libraryPaths;
-       std::vector<const char*> frameworkPaths;
-       // scan through argv looking for -L, -F, -Z, and -syslibroot options
-       for(int i=0; i < argc; ++i) {
-               if ( (argv[i][0] == '-') && (argv[i][1] == 'L') )
-                       libraryPaths.push_back(&argv[i][2]);
-               else if ( (argv[i][0] == '-') && (argv[i][1] == 'F') )
-                       frameworkPaths.push_back(&argv[i][2]);
-               else if ( strcmp(argv[i], "-Z") == 0 )
-                       addStandardLibraryDirectories = false;
-               else if ( strcmp(argv[i], "-v") == 0 ) {
-                       fVerbose = true;
-                       extern const char ld64VersionString[];
-                       fprintf(stderr, "%s", ld64VersionString);
-                        // if only -v specified, exit cleanly
-                        if ( argc == 2 )
-                               exit(0);
-               }
-               else if ( strcmp(argv[i], "-syslibroot") == 0 ) {
-                       const char* path = argv[++i];
-                       if ( path == NULL )
-                               throw "-syslibroot missing argument";
-                       fSDKPaths.push_back(path);
-               }
-       }
-       if ( addStandardLibraryDirectories ) {
-               libraryPaths.push_back("/usr/lib");
-               libraryPaths.push_back("/usr/local/lib");
-               
-               frameworkPaths.push_back("/Library/Frameworks/");
-               frameworkPaths.push_back("/Network/Library/Frameworks/");
-               frameworkPaths.push_back("/System/Library/Frameworks/");
-       }
-       
-       // now merge sdk and library paths to make real search paths
-       for (std::vector<const char*>::iterator it = libraryPaths.begin(); it != libraryPaths.end(); it++) {
-               const char* libDir = *it;
-               bool sdkOverride = false;
-               if ( libDir[0] == '/' ) {
-                       char betterLibDir[PATH_MAX];
-                       if ( strstr(libDir, "/..") != NULL ) {
-                               if ( realpath(libDir, betterLibDir) != NULL )
-                                       libDir = betterLibDir;
-                       }
-                       const int libDirLen = strlen(libDir);
-                       for (std::vector<const char*>::iterator sdkit = fSDKPaths.begin(); sdkit != fSDKPaths.end(); sdkit++) {
-                               const char* sdkDir = *sdkit;
-                               const int sdkDirLen = strlen(sdkDir);
-                               char newPath[libDirLen + sdkDirLen+4];
-                               strcpy(newPath, sdkDir);
-                               if ( newPath[sdkDirLen-1] == '/' )
-                                       newPath[sdkDirLen-1] = '\0';
-                               strcat(newPath, libDir);
-                               struct stat statBuffer;
-                               if ( stat(newPath, &statBuffer) == 0 ) {
-                                       fLibrarySearchPaths.push_back(strdup(newPath));
-                                       sdkOverride = true;
-                               }
-                       }
-               }
-               if ( !sdkOverride ) 
-                       fLibrarySearchPaths.push_back(libDir);
-       }
-       
-       // now merge sdk and framework paths to make real search paths
-       for (std::vector<const char*>::iterator it = frameworkPaths.begin(); it != frameworkPaths.end(); it++) {
-               const char* frameworkDir = *it;
-               bool sdkOverride = false;
-               if ( frameworkDir[0] == '/' ) {
-                       char betterFrameworkDir[PATH_MAX];
-                       if ( strstr(frameworkDir, "/..") != NULL ) {
-                               if ( realpath(frameworkDir, betterFrameworkDir) != NULL )
-                                       frameworkDir = betterFrameworkDir;
-                       }
-                       const int frameworkDirLen = strlen(frameworkDir);
-                       for (std::vector<const char*>::iterator sdkit = fSDKPaths.begin(); sdkit != fSDKPaths.end(); sdkit++) {
-                               const char* sdkDir = *sdkit;
-                               const int sdkDirLen = strlen(sdkDir);
-                               char newPath[frameworkDirLen + sdkDirLen+4];
-                               strcpy(newPath, sdkDir);
-                               if ( newPath[sdkDirLen-1] == '/' )
-                                       newPath[sdkDirLen-1] = '\0';
-                               strcat(newPath, frameworkDir);
-                               struct stat statBuffer;
-                               if ( stat(newPath, &statBuffer) == 0 ) {
-                                       fFrameworkSearchPaths.push_back(strdup(newPath));
-                                       sdkOverride = true;
-                               }
-                       }
-               }
-               if ( !sdkOverride ) 
-                       fFrameworkSearchPaths.push_back(frameworkDir);
-       }
-       
-       if ( fVerbose ) {
-               fprintf(stderr,"Library search paths:\n");
-               for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin(); it != fLibrarySearchPaths.end(); it++)
-                       fprintf(stderr,"\t%s\n", *it);
-               fprintf(stderr,"Framework search paths:\n");
-               for (std::vector<const char*>::iterator it = fFrameworkSearchPaths.begin(); it != fFrameworkSearchPaths.end(); it++)
-                       fprintf(stderr,"\t%s\n", *it);
-       }
-}
-
-// this is run before the command line is parsed
-void Options::parsePreCommandLineEnvironmentSettings()
-{
-       if ( getenv("RC_TRACE_ARCHIVES") != NULL)
-           fReaderOptions.fTraceArchives = true;
-               
-       if ( getenv("RC_TRACE_DYLIBS") != NULL) {
-           fReaderOptions.fTraceDylibs = true;
-               fReaderOptions.fTraceIndirectDylibs = true;
-       }
-}
-
-// this is run after the command line is parsed
-void Options::parsePostCommandLineEnvironmentSettings()
-{
-
-}
-
-void Options::checkIllegalOptionCombinations()
-{
-       // check -undefined setting
-       switch ( fUndefinedTreatment ) {
-               case kUndefinedError:
-               case kUndefinedDynamicLookup:
-                       // always legal
-                       break;
-               case kUndefinedWarning:
-               case kUndefinedSuppress:
-                       // requires flat namespace
-                       if ( fNameSpace == kTwoLevelNameSpace )
-                               throw "can't use -undefined warning or suppress with -twolevel_namespace";
-                       break;
-       }
-       
-       // unify -sub_umbrella with dylibs
-       for (std::vector<const char*>::iterator it = fSubUmbellas.begin(); it != fSubUmbellas.end(); it++) {
-               const char* subUmbrella = *it;
-               bool found = false;
-               for (std::vector<Options::FileInfo>::iterator fit = fInputFiles.begin(); fit != fInputFiles.end(); fit++) {
-                       Options::FileInfo& info = *fit;
-                       const char* lastSlash = strrchr(info.path, '/');
-                       if ( lastSlash == NULL )
-                               lastSlash = info.path - 1;
-                       if ( strcmp(&lastSlash[1], subUmbrella) == 0 ) {
-                               info.options.fReExport = true;
-                               found = true;
-                               break;
-                       }
-               }
-               if ( ! found )
-                       fprintf(stderr, "ld64 warning: -sub_umbrella %s does not match a supplied dylib\n", subUmbrella);
-       }
-       
-       // unify -sub_library with dylibs
-       for (std::vector<const char*>::iterator it = fSubLibraries.begin(); it != fSubLibraries.end(); it++) {
-               const char* subLibrary = *it;
-               bool found = false;
-               for (std::vector<Options::FileInfo>::iterator fit = fInputFiles.begin(); fit != fInputFiles.end(); fit++) {
-                       Options::FileInfo& info = *fit;
-                       const char* lastSlash = strrchr(info.path, '/');
-                       if ( lastSlash == NULL )
-                               lastSlash = info.path - 1;
-                       const char* dot = strchr(lastSlash, '.');
-                       if ( dot == NULL )
-                               dot = &lastSlash[strlen(lastSlash)];
-                       if ( strncmp(&lastSlash[1], subLibrary, dot-lastSlash-1) == 0 ) {
-                               info.options.fReExport = true;
-                               found = true;
-                               break;
-                       }
-               }
-               if ( ! found )
-                       fprintf(stderr, "ld64 warning: -sub_library %s does not match a supplied dylib\n", subLibrary);
-       }
-       
-       // sync reader options
-       if ( fNameSpace != kTwoLevelNameSpace )
-               fReaderOptions.fFlatNamespace = true;
-
-       // check -stack_addr
-       if ( fStackAddr != 0 ) { 
-               switch (fArchitecture) {
-                       case CPU_TYPE_I386:
-                       case CPU_TYPE_POWERPC:
-                               if ( fStackAddr > 0xFFFFFFFF ) 
-                                       throw "-stack_addr must be < 4G for 32-bit processes";
-                               break;
-                       case CPU_TYPE_POWERPC64:
-                               break;
-               }
-               if ( (fStackAddr & -4096) != fStackAddr )
-                       throw "-stack_addr must be multiples of 4K";
-               if ( fStackSize  == 0 )
-                       throw "-stack_addr must be used with -stack_size";
-       }
-       
-       // check -stack_size
-       if ( fStackSize != 0 ) { 
-               switch (fArchitecture) {
-                       case CPU_TYPE_I386:
-                       case CPU_TYPE_POWERPC:
-                               if ( fStackSize > 0xFFFFFFFF ) 
-                                       throw "-stack_size must be < 4G for 32-bit processes";
-                               if ( fStackAddr == 0 ) {
-                                       fprintf(stderr, "ld64 warning: -stack_addr not specified, using the default 0xC0000000\n");
-                                       fStackAddr = 0xC0000000;
-                               }
-                               break;
-                       case CPU_TYPE_POWERPC64:
-                               if ( fStackAddr == 0 ) {
-                                       fprintf(stderr, "ld64 warning: -stack_addr not specified, using the default 0x0008000000000000\n");
-                                       fStackAddr = 0x0008000000000000LL;
-                               }
-                               break;
-               }
-               if ( (fStackSize & -4096) != fStackSize )
-                       throw "-stack_size must be multiples of 4K";
-               switch ( fOutputKind ) {
-                       case Options::kDynamicExecutable:
-                       case Options::kStaticExecutable:
-                               // custom stack size only legeal when building main executable
-                               break;
-                       case Options::kDynamicLibrary:
-                       case Options::kDynamicBundle:
-                       case Options::kObjectFile:
-                       case Options::kDyld:
-                               throw "-stack_size option can only be used when linking a main executable";
-               }
-       }
-       
-       // check -init is only used when building a dylib
-       if ( (fInitFunctionName != NULL) && (fOutputKind != Options::kDynamicLibrary) )
-               throw "-init can only be used with -dynamiclib";
-               
-       // make sure all required exported symbols exist
-       for (NameSet::iterator it=fExportSymbols.begin(); it != fExportSymbols.end(); it++)
-               fInitialUndefines.push_back(*it);
-               
-}
-
-
index 520b30428d2d6e0b66373a8972c689f2ff93fb3a..c8ef861235e9cbb4c8f833523eb7956594fe28fc 100644 (file)
@@ -1,16 +1,16 @@
-/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+/* -*- 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,
@@ -18,7 +18,7 @@
  * 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 <mach/machine.h>
 
-#ifndef CPU_TYPE_POWERPC64
-#define CPU_TYPE_POWERPC64 0x1000012
-#endif
-
-
 #include <vector>
 #include <ext/hash_set>
 
 #include "ObjectFile.h"
 
-extern  __attribute__((noreturn)) void throwf(const char* format, ...);
-
+void throwf (const char* format, ...) __attribute__ ((noreturn));
 
-class DynamicLibraryOptions 
+class DynamicLibraryOptions
 {
 public:
-                               DynamicLibraryOptions() : fWeakImport(false), fReExport(false), fInstallPathOverride(NULL) {}
-                               
+       DynamicLibraryOptions() : fWeakImport(false), fReExport(false), fInstallPathOverride(NULL) {}
+
        bool            fWeakImport;
        bool            fReExport;
        const char* fInstallPathOverride;
 };
 
-
+//
+// The public interface to the Options class is the abstract representation of what work the linker
+// should do.
+//
+// This abstraction layer will make it easier to support a future where the linker is a shared library
+// invoked directly from Xcode.  The target settings in Xcode would be used to directly construct an Options
+// object (without building a command line which is then parsed).
+//
+//
 class Options
 {
 public:
-                                                               Options(int argc, const char* argv[]);
-                                                               ~Options();
+       Options(int argc, const char* argv[]);
+       ~Options();
 
        enum OutputKind { kDynamicExecutable, kStaticExecutable, kDynamicLibrary, kDynamicBundle, kObjectFile, kDyld };
        enum NameSpace { kTwoLevelNameSpace, kFlatNameSpace, kForceFlatNameSpace };
+       // Standard treatment for many options.
+       enum Treatment { kError, kWarning, kSuppress, kNULL, kInvalid };
        enum UndefinedTreatment { kUndefinedError, kUndefinedWarning, kUndefinedSuppress, kUndefinedDynamicLookup };
-       enum PICTreatment { kPICError, kPICWarning, kPICSuppress };
-       enum WeakReferenceMismatchTreatment { kWeakReferenceMismatchError, kWeakReferenceMismatchWeak, kWeakReferenceMismatchNonWeak };
+       enum WeakReferenceMismatchTreatment { kWeakReferenceMismatchError, kWeakReferenceMismatchWeak,
+                                                                                 kWeakReferenceMismatchNonWeak };
        enum CommonsMode { kCommonsIgnoreDylibs, kCommonsOverriddenByDylibs, kCommonsConflictsDylibsError };
+       enum DeadStripMode { kDeadStripOff, kDeadStripOn, kDeadStripOnPlusUnusedInits };
+       enum VersionMin { k10_1, k10_2, k10_3, k10_4, k10_5 };
 
        struct FileInfo {
                const char*                             path;
                uint64_t                                fileLen;
+               time_t                                  modTime;
                DynamicLibraryOptions   options;
        };
-       
+
        struct ExtraSection {
                const char*                             segmentName;
                const char*                             sectionName;
@@ -79,21 +86,21 @@ public:
                const uint8_t*                  data;
                uint64_t                                dataLen;
        };
-       
+
        struct SectionAlignment {
                const char*                             segmentName;
                const char*                             sectionName;
                uint8_t                                 alignment;
        };
 
-       ObjectFile::ReaderOptions&      readerOptions();
-       const char*                                     getOutputFilePath();
-       std::vector<FileInfo>&          getInputFiles();
-       
+       const ObjectFile::ReaderOptions&        readerOptions();
+       const char*                                                     getOutputFilePath();
+       std::vector<FileInfo>&                          getInputFiles();
+
        cpu_type_t                                      architecture();
        OutputKind                                      outputKind();
        bool                                            stripLocalSymbols();
-       bool                                            stripDebugInfo();
+       bool                                            prebind();
        bool                                            bindAtLoad();
        bool                                            fullyLoadArchives();
        NameSpace                                       nameSpace();
@@ -101,32 +108,48 @@ public:
        uint32_t                                        currentVersion();               // only for kDynamicLibrary
        uint32_t                                        compatibilityVersion(); // only for kDynamicLibrary
        const char*                                     entryName();                    // only for kDynamicExecutable or kStaticExecutable
+       const char*                                     executablePath();
        uint64_t                                        baseAddress();
        bool                                            keepPrivateExterns();   // only for kObjectFile
-       bool                                            interposable();                 // only for kDynamicLibrary 
+       bool                                            interposable();                 // only for kDynamicLibrary
        bool                                            hasExportRestrictList();
        bool                                            shouldExport(const char*);
        bool                                            ignoreOtherArchInputFiles();
        bool                                            forceCpuSubtypeAll();
        bool                                            traceDylibs();
        bool                                            traceArchives();
+       DeadStripMode                           deadStrip();
        UndefinedTreatment                      undefinedTreatment();
+       VersionMin                                      macosxVersionMin();
        bool                                            messagesPrefixedWithArchitecture();
-       PICTreatment                            picTreatment();
+       Treatment                                       picTreatment();
        WeakReferenceMismatchTreatment  weakReferenceMismatchTreatment();
+       Treatment                                       multipleDefinitionsInDylibs();
+       Treatment                                       overridingDefinitionInDependentDylib();
+       bool                                            warnOnMultipleDefinitionsInObjectFiles();
        const char*                                     umbrellaName();
+       std::vector<const char*>&       allowableClients();
+       const char*                                     clientName();
        const char*                                     initFunctionName();                     // only for kDynamicLibrary
+       const char*                                     dotOutputFile();
        uint64_t                                        zeroPageSize();
        bool                                            hasCustomStack();
        uint64_t                                        customStackSize();
        uint64_t                                        customStackAddr();
+       bool                                            hasExecutableStack();
        std::vector<const char*>&       initialUndefines();
        uint32_t                                        minimumHeaderPad();
        std::vector<ExtraSection>&      extraSections();
        std::vector<SectionAlignment>&  sectionAlignments();
        CommonsMode                                     commonsMode();
        bool                                            warnCommons();
+       bool                                            keepRelocations();
+       std::vector<const char*>&   traceSymbols();
        FileInfo                                        findFile(const char* path);
+       bool                                            emitUUID();
+       bool                                            warnStabs();
+       bool                                            pauseAtEnd() { return fPause; }
+       bool                                            printStatistics() { return fStatistics; }
 
 private:
        class CStringEquals
@@ -145,7 +168,8 @@ private:
        void                                            parseArch(const char* architecture);
        FileInfo                                        findLibrary(const char* rootName);
        FileInfo                                        findFramework(const char* rootName);
-       bool                                            checkForFile(const char* format, const char* dir, const char* rootName, FileInfo& result);
+       bool                                            checkForFile(const char* format, const char* dir, const char* rootName,
+                                                                                        FileInfo& result);
        uint32_t                                        parseVersionNumber(const char*);
        void                                            parseSectionOrderFile(const char* segment, const char* section, const char* path);
        void                                            addSection(const char* segment, const char* section, const char* path);
@@ -156,27 +180,29 @@ private:
        void                                            parsePreCommandLineEnvironmentSettings();
        void                                            parsePostCommandLineEnvironmentSettings();
        void                                            setUndefinedTreatment(const char* treatment);
-       void                                            setPICTreatment(const char* treatment);
-       void                                            setReadOnlyRelocTreatment(const char* treatment);
+       void                                            setVersionMin(const char* version);
        void                                            setWeakReferenceMismatchTreatment(const char* treatment);
        void                                            setDylibInstallNameOverride(const char* paths);
-       void                                            setExecutablePath(const char* path);
        void                                            addSectionAlignment(const char* segment, const char* section, const char* alignment);
        CommonsMode                                     parseCommonsTreatment(const char* mode);
-               
-               
+       Treatment                                       parseTreatment(const char* treatment);
+
+
 
        ObjectFile::ReaderOptions                       fReaderOptions;
        const char*                                                     fOutputFile;
        std::vector<Options::FileInfo>          fInputFiles;
        cpu_type_t                                                      fArchitecture;
        OutputKind                                                      fOutputKind;
+       bool                                                            fPrebind;
        bool                                                            fBindAtLoad;
        bool                                                            fStripLocalSymbols;
        bool                                                            fKeepPrivateExterns;
        bool                                                            fInterposable;
        bool                                                            fIgnoreOtherArchFiles;
        bool                                                            fForceSubtypeAll;
+       DeadStripMode                                           fDeadStrip;
+       VersionMin                                                      fVersionMin;
        NameSpace                                                       fNameSpace;
        uint32_t                                                        fDylibCompatVersion;
        uint32_t                                                        fDylibCurrentVersion;
@@ -189,26 +215,44 @@ private:
        LibrarySearchMode                                       fLibrarySearchMode;
        UndefinedTreatment                                      fUndefinedTreatment;
        bool                                                            fMessagesPrefixedWithArchitecture;
-       PICTreatment                                            fPICTreatment;
+       Treatment                                                       fPICTreatment;
        WeakReferenceMismatchTreatment          fWeakReferenceMismatchTreatment;
+       Treatment                                                       fMultiplyDefinedDynamic;
+       Treatment                                                       fMultiplyDefinedUnused;
+       bool                                                            fWarnOnMultiplyDefined;
        std::vector<const char*>                        fSubUmbellas;
        std::vector<const char*>                        fSubLibraries;
+       std::vector<const char*>                        fAllowableClients;
+       const char*                                                     fClientName;
        const char*                                                     fUmbrellaName;
        const char*                                                     fInitFunctionName;
+       const char*                                                     fDotOutputFile;
+       const char*                                                     fExecutablePath;
        uint64_t                                                        fZeroPageSize;
        uint64_t                                                        fStackSize;
        uint64_t                                                        fStackAddr;
+       bool                                                            fExecutableStack;
        uint32_t                                                        fMinimumHeaderPad;
        CommonsMode                                                     fCommonsMode;
        bool                                                            fWarnCommons;
        bool                                                            fVerbose;
+       bool                                                            fKeepRelocations;
+       bool                                                            fEmitUUID;
+       bool                                                            fWarnStabs;
+       bool                                                            fTraceDylibSearching;
+       bool                                                            fPause;
+       bool                                                            fStatistics;
+       bool                                                            fPrintOptions;
        std::vector<const char*>                        fInitialUndefines;
+       std::vector<const char*>                        fTraceSymbols;
+       unsigned long                                           fLimitUndefinedSymbols;
        std::vector<ExtraSection>                       fExtraSections;
        std::vector<SectionAlignment>           fSectionAlignments;
-       
+
        std::vector<const char*>                        fLibrarySearchPaths;
        std::vector<const char*>                        fFrameworkSearchPaths;
        std::vector<const char*>                        fSDKPaths;
+       bool                                                            fAllowStackExecute;
 
 };
 
@@ -216,14 +260,3 @@ private:
 
 
 #endif // __OPTIONS__
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/Readers/ObjectFileArchiveMachO.cpp b/src/Readers/ObjectFileArchiveMachO.cpp
deleted file mode 100644 (file)
index b01d8a0..0000000
+++ /dev/null
@@ -1,324 +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@
- */
-
-
-
-namespace ObjectFileArchiveMachO {
-
-class Reader : public ObjectFile::Reader 
-{
-public:
-                                                                                               Reader(const uint8_t fileContent[], uint64_t fileLength, const char* path, const ObjectFile::ReaderOptions& options);
-       virtual                                                                         ~Reader();
-       
-       virtual const char*                                                             getPath();
-       virtual std::vector<class ObjectFile::Atom*>&   getAtoms();
-       virtual std::vector<class ObjectFile::Atom*>*   getJustInTimeAtomsFor(const char* name);
-       virtual std::vector<ObjectFile::StabsInfo>*             getStabsDebugInfo();
-
-private:
-       class Entry : ar_hdr
-       {
-       public:
-               const char*                     getName() const;
-               const uint8_t*          getContent() const;
-               uint32_t                        getContentSize() const;
-               const Entry*            getNext() const;
-       private:
-               bool                            hasLongName() const;
-               unsigned int            getLongNameSpace() const;
-               
-       };
-
-       const struct ranlib*                                                    ranlibBinarySearch(const char* name);
-       const struct ranlib*                                                    ranlibLinearSearch(const char* name);
-       ObjectFile::Reader*                                                             makeObjectReaderForMember(const Entry* member);
-       void                                                                                    dumpTableOfContents();
-       
-       const char*                                                                             fPath;
-       const ObjectFile::ReaderOptions&                                fOptions;
-       const uint8_t*                                                                  fFileContent;
-       uint64_t                                                                                fFileLength;
-       const struct ranlib*                                                    fTableOfContents;
-       uint32_t                                                                                fTableOfContentCount;
-       bool                                                                                    fSorted;
-       const char*                                                                             fStringPool;
-       std::vector<class ObjectFile::Atom*>                    fAllAtoms;
-       std::set<const class Entry*>                                    fInstantiatedEntries;
-       
-       static std::vector<class ObjectFile::Atom*>             fgEmptyList;
-};
-
-std::vector<class ObjectFile::Atom*>           Reader::fgEmptyList;
-
-#undef SwapArchToHostInt32
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
-       #define SwapArchToHostInt32(value) OSSwapBigToHostInt32(value)
-#elif defined(ARCH_I386)
-       #define SwapArchToHostInt32(value) OSSwapLittleToHostInt32(value)
-#endif
-
-
-
-bool Reader::Entry::hasLongName() const
-{
-       return ( strncmp(this->ar_name, AR_EFMT1, strlen(AR_EFMT1)) == 0 );
-}
-
-unsigned int Reader::Entry::getLongNameSpace() const
-{
-       char* endptr;
-       long result = strtol(&this->ar_name[strlen(AR_EFMT1)], &endptr, 10);
-       return result;
-}
-
-const char* Reader::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;
-       }
-}
-
-
-const uint8_t* Reader::Entry::getContent() const
-{
-       if ( this->hasLongName() ) 
-               return ((uint8_t*)this) + sizeof(ar_hdr) + this->getLongNameSpace();
-       else
-               return ((uint8_t*)this) + sizeof(ar_hdr);
-}
-
-
-uint32_t Reader::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;
-}
-
-const Reader::Entry*   Reader::Entry::getNext() const
-{
-       const uint8_t* p = this->getContent() + getContentSize();
-       p = (const uint8_t*)(((uintptr_t)p+3) & (-4));  // 4-byte align
-       return (Reader::Entry*)p;
-}
-
-
-
-Reader::Reader(const uint8_t fileContent[], uint64_t fileLength, const char* path, const ObjectFile::ReaderOptions& options)
- : fPath(NULL), fOptions(options), fFileContent(NULL), fTableOfContents(NULL), fTableOfContentCount(0),
-   fSorted(false), fStringPool(NULL)
-{
-       fPath = strdup(path);
-       fFileContent = fileContent;
-       fFileLength = fileLength;
-
-       if ( strncmp((const char*)fileContent, "!<arch>\n", 8) != 0 )
-               throw "not an archive";
-       
-       if ( !options.fFullyLoadArchives ) {
-               const Entry* const firstMember = (Entry*)&fFileContent[8];
-               if ( strcmp(firstMember->getName(), SYMDEF_SORTED) == 0 )
-                       fSorted = true;
-               else if ( strcmp(firstMember->getName(), SYMDEF) == 0 )
-                       fSorted = false;
-               else
-                       throw "archive has no table of contents";
-               const uint8_t* contents = firstMember->getContent();
-               uint32_t ranlibArrayLen = SwapArchToHostInt32(*((uint32_t*)contents));
-               fTableOfContents = (const struct ranlib*)&contents[4];
-               fTableOfContentCount = ranlibArrayLen / sizeof(struct ranlib);
-               fStringPool = (const char*)&contents[ranlibArrayLen+8];
-       }
-       
-       if ( options.fTraceArchives )
-               printf("[Logging for Build & Integration] Used static archive: %s\n", fPath);
-}
-
-Reader::~Reader()
-{
-}
-
-
-
-ObjectFile::Reader* Reader::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 {
-               return ObjectFileMachO::MakeReader((class macho_header*)member->getContent(), memberPath, fOptions);
-       }
-       catch (const char* msg) {
-               throwf("in %s, %s", memberPath, msg);
-       }
-}
-
-const char* Reader::getPath()
-{
-       return fPath;
-}
-
-std::vector<class ObjectFile::Atom*>&  Reader::getAtoms()
-{
-       if ( fOptions.fFullyLoadArchives ) {
-               // 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) )
-                               continue;
-                       ObjectFile::Reader* r = this->makeObjectReaderForMember(p);
-                       std::vector<class ObjectFile::Atom*>&   atoms = r->getAtoms();
-                       fAllAtoms.insert(fAllAtoms.end(), atoms.begin(), atoms.end());
-               }
-               return fAllAtoms;
-       }
-       else {
-               // return nonthing for now, getJustInTimeAtomsFor() will return atoms as needed
-               return fgEmptyList;
-       }
-}
-
-
-const struct ranlib* Reader::ranlibBinarySearch(const char* key)
-{
-       const struct ranlib* base = fTableOfContents;
-       for (uint32_t n = fTableOfContentCount; n > 0; n /= 2) {
-               const struct ranlib* pivot = &base[n/2];
-               const char* pivotStr = &fStringPool[SwapArchToHostInt32(pivot->ran_un.ran_strx)];
-               int cmp = strcmp(key, pivotStr);
-               if ( cmp == 0 )
-                       return pivot;
-               if ( cmp > 0 ) {
-                       // key > pivot 
-                       // move base to symbol after pivot
-                       base = &pivot[1];
-                       --n; 
-               }
-               else {
-                       // key < pivot 
-                       // keep same base
-               }
-       }
-       return NULL;
-}
-
-const struct ranlib* Reader::ranlibLinearSearch(const char* key)
-{
-       for (uint32_t i = 0; i < fTableOfContentCount; ++i) {
-               const struct ranlib* entry = &fTableOfContents[i];
-               const char* entryName = &fStringPool[SwapArchToHostInt32(entry->ran_un.ran_strx)];
-               if ( strcmp(key, entryName) == 0 )
-                       return entry;
-       }
-       return NULL;
-}
-
-
-void Reader::dumpTableOfContents()
-{
-       for (unsigned int i=0; i < fTableOfContentCount; ++i) {
-               const struct ranlib* e = &fTableOfContents[i];
-               printf("%s in %s\n", &fStringPool[SwapArchToHostInt32(e->ran_un.ran_strx)], ((Entry*)&fFileContent[SwapArchToHostInt32(e->ran_off)])->getName());
-       }
-}
-
-std::vector<class ObjectFile::Atom*>* Reader::getJustInTimeAtomsFor(const char* name)
-{
-       if ( fOptions.fFullyLoadArchives ) {
-               return NULL;
-       }
-       else {
-               const struct ranlib* result = NULL;
-               if ( fSorted ) {
-                       // do a binary search of table of contents looking for requested symbol
-                       result = ranlibBinarySearch(name);
-               }
-               else {
-                       // do a linear search of table of contents looking for requested symbol
-                       result = ranlibLinearSearch(name);
-               }
-               if ( result != NULL ) {
-                       const Entry* member = (Entry*)&fFileContent[SwapArchToHostInt32(result->ran_off)];
-                       if ( fInstantiatedEntries.count(member) == 0 ) {
-                               // only return these atoms once
-                               fInstantiatedEntries.insert(member);
-                               ObjectFile::Reader* r = makeObjectReaderForMember(member);
-                               //fprintf(stderr, "%s found in %s\n", name, member->getName());
-                               return new std::vector<class ObjectFile::Atom*>(r->getAtoms());
-                       }
-               }
-               //fprintf(stderr, "%s NOT found in archive %s\n", name, fPath);
-               return NULL; 
-       }
-}
-
-
-std::vector<ObjectFile::StabsInfo>*    Reader::getStabsDebugInfo()
-{
-       return NULL;
-}
-
-
-
-Reader* MakeReader(const uint8_t fileContent[], uint64_t fileLength, const char* path, const ObjectFile::ReaderOptions& options)
-{
-       return new Reader(fileContent, fileLength, path, options);
-}
-
-
-
-};
-
-
-
-
-
-
-
diff --git a/src/Readers/ObjectFileDylibMachO.cpp b/src/Readers/ObjectFileDylibMachO.cpp
deleted file mode 100644 (file)
index fad4dcb..0000000
+++ /dev/null
@@ -1,485 +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@
- */
-
-
-
-namespace ObjectFileDylibMachO {
-
-class Reader : public ObjectFile::Reader 
-{
-public:
-                                                                                               Reader(const macho_header* header, const char* path, const ObjectFile::ReaderOptions& options);
-       virtual                                                                         ~Reader();
-                                                                                               
-       virtual const char*                                                             getPath();
-       virtual std::vector<class ObjectFile::Atom*>&   getAtoms();
-       virtual std::vector<class ObjectFile::Atom*>*   getJustInTimeAtomsFor(const char* name);
-       virtual std::vector<ObjectFile::StabsInfo>*             getStabsDebugInfo();
-       virtual const char*                                                             getInstallPath();
-       virtual uint32_t                                                                getTimestamp();
-       virtual uint32_t                                                                getCurrentVersion();
-       virtual uint32_t                                                                getCompatibilityVersion();
-       virtual std::vector<const char*>*                               getDependentLibraryPaths();
-       virtual bool                                                                    reExports(ObjectFile::Reader*);
-       virtual bool                                                                    isDefinitionWeak(const ObjectFile::Atom&);
-       
-private:
-       struct CStringComparor
-       {
-                bool operator()(const char* left, const char* right) { return (strcmp(left, right) > 0); }
-       };
-       typedef std::map<const char*, ObjectFile::Atom*, CStringComparor> Mapper;
-
-
-       void                                                                            init(const macho_header* header,const char* path);
-       const macho_nlist*                                                      binarySearchWithToc(const char* key, const char stringPool[], const macho_nlist symbols[], const struct dylib_table_of_contents toc[], uint32_t symbolCount);
-       const macho_nlist*                                                      binarySearch(const char* key, const char stringPool[], const macho_nlist symbols[], uint32_t symbolCount);
-       bool                                                                            hasExport(const char* name);
-       const macho_nlist*                                                      findExport(const char* name);
-       
-       const char*                                                                     fPath;
-       const macho_header*                                                     fHeader;
-       const char*                                                                     fStrings;
-       const macho_dysymtab_command*                           fDynamicInfo;
-       const macho_dylib_command*                                      fDylibID;
-       const macho_nlist*                                                      fSymbols;
-       uint32_t                                                                        fSymbolCount;
-       Mapper                                                                          fAtoms;
-       std::vector<Reader*>                                            fReExportedDylibs;
-
-       static std::vector<class ObjectFile::Atom*>     fEmptyAtomList;
-};
-
-std::vector<class ObjectFile::Atom*>   Reader::fEmptyAtomList;
-
-
-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;
-};
-
-
-class ExportAtom : public ObjectFile::Atom
-{
-public:
-       virtual ObjectFile::Reader*                                     getFile() const                         { return &fOwner; }
-       virtual const char*                                                     getName() const                         { return fName; }
-       virtual const char*                                                     getDisplayName() const;
-       virtual Scope                                                           getScope() const                        { return ObjectFile::Atom::scopeGlobal; }
-       virtual bool                                                            isTentativeDefinition() const { return false; }
-       virtual bool                                                            isWeakDefinition() const        { return false; }
-       virtual bool                                                            isCoalesableByName() const      { return false; }
-       virtual bool                                                            isCoalesableByValue() const { return false; }
-       virtual bool                                                            isZeroFill() const                      { return false; }
-       virtual bool                                                            dontDeadStrip() const           { return false; }
-       virtual bool                                                            dontStripName() const           { return false; }
-       virtual bool                                                            isImportProxy() const           { return true; }
-       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 bool                                                            requiresFollowOnAtom() const{ return false; }
-       virtual ObjectFile::Atom&                                       getFollowOnAtom() const         { return *((ObjectFile::Atom*)NULL); }
-       virtual std::vector<ObjectFile::StabsInfo>*     getStabsDebugInfo() const       { return NULL; }
-       virtual uint8_t                                                         getAlignment() const            { return 0; }
-       virtual WeakImportSetting                                       getImportWeakness() const       { return fWeakImportSetting; }
-       virtual void                                                            copyRawContent(uint8_t buffer[]) const  {}
-       virtual void                                                            writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const {}
-
-       virtual void                                                            setScope(Scope)                         { }
-       virtual void                                                            setImportWeakness(bool weakImport) { fWeakImportSetting = weakImport ? kWeakImport : kNonWeakImport; }
-
-protected:
-       friend class Reader;
-       
-                                                                                       ExportAtom(Reader& owner, const char* name)  : fOwner(owner), fName(name), fWeakImportSetting(kWeakUnset) {}
-       virtual                                                                 ~ExportAtom() {}
-       
-       Reader&                                                                 fOwner;
-       const char*                                                             fName;
-       WeakImportSetting                                               fWeakImportSetting;
-       
-       static std::vector<ObjectFile::Reference*>      fgEmptyReferenceList;
-       static Segment                                                          fgImportSegment;
-};
-
-Segment                                                                ExportAtom::fgImportSegment("__LINKEDIT");
-std::vector<ObjectFile::Reference*>    ExportAtom::fgEmptyReferenceList;
-
-const char* ExportAtom::getDisplayName() const
-{
-       static char temp[300];
-       strcpy(temp, fName);
-       strcat(temp, "$import");
-       return temp;
-}
-
-
-
-Reader::Reader(const macho_header* header, const char* path, const ObjectFile::ReaderOptions& options)
- : fHeader(header), fStrings(NULL), fDylibID(NULL), fSymbols(NULL), fSymbolCount(0)
-{
-       typedef std::pair<const macho_dylib_command*, bool> DylibAndReExportFlag;
-       std::vector<DylibAndReExportFlag>               dependentDylibs;
-
-       fPath = strdup(path);
-       const uint32_t cmd_count = header->ncmds();
-       const macho_load_command* const cmds = (macho_load_command*)((char*)header + macho_header::size);
-       // get all dylib load commands
-       const macho_load_command* cmd = cmds;
-       for (uint32_t i = 0; i < cmd_count; ++i) {
-               switch (cmd->cmd()) {
-                       case LC_LOAD_DYLIB:
-                       case LC_LOAD_WEAK_DYLIB:
-                               {
-                                       DylibAndReExportFlag info;
-                                       info.first = (struct macho_dylib_command*)cmd;
-                                       info.second = options.fFlatNamespace;
-                                       dependentDylibs.push_back(info);
-                               }
-                               break;
-               }
-               cmd = (const macho_load_command*)(((char*)cmd)+cmd->cmdsize());
-       }
-       
-       // cache interesting pointers
-       cmd = cmds;
-       for (uint32_t i = 0; i < cmd_count; ++i) {
-               switch (cmd->cmd()) {
-                       case LC_SYMTAB:
-                               {
-                                       const macho_symtab_command* symtab = (macho_symtab_command*)cmd;
-                                       fSymbolCount = symtab->nsyms();
-                                       fSymbols = (const macho_nlist*)((char*)header + symtab->symoff());
-                                       fStrings = (char*)header + symtab->stroff();
-                               }
-                               break;
-                       case LC_DYSYMTAB:
-                               fDynamicInfo = (macho_dysymtab_command*)cmd;
-                               break;
-                       case LC_ID_DYLIB:
-                               fDylibID = (macho_dylib_command*)cmd;
-                               break;
-                       case LC_SUB_UMBRELLA:
-                               if ( !options.fFlatNamespace ) {
-                                       const char* frameworkLeafName = ((macho_sub_umbrella_command*)cmd)->name();
-                                       for (std::vector<DylibAndReExportFlag>::iterator it = dependentDylibs.begin(); it != dependentDylibs.end(); it++) {
-                                               const char* dylibName = it->first->name();
-                                               const char* lastSlash = strrchr(dylibName, '/');
-                                               if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], frameworkLeafName) == 0) )
-                                                       it->second = true;
-                                       }
-                               }
-                               break;
-                       case LC_SUB_LIBRARY:
-                               if ( !options.fFlatNamespace ) {
-                                       const char* dylibBaseName = ((macho_sub_library_command*)cmd)->name();
-                                       for (std::vector<DylibAndReExportFlag>::iterator it = dependentDylibs.begin(); it != dependentDylibs.end(); it++) {
-                                               const char* dylibName = it->first->name();
-                                               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->second = true;
-                                       }
-                               }
-                               break;
-               }
-               cmd = (const macho_load_command*)(((char*)cmd)+cmd->cmdsize());
-       }
-       
-       // load dylibs we need to re-export
-       for (std::vector<DylibAndReExportFlag>::iterator it = dependentDylibs.begin(); it != dependentDylibs.end(); it++) {
-               if ( it->second ) {
-                       // printf("%s need to re-export %s\n", path, it->first->name());
-                       //fReExportedDylibs.push_back(
-               }
-       }
-}
-
-
-Reader::~Reader()
-{
-}
-
-const char*     Reader::getPath()
-{
-       return fPath;
-}
-
-
-std::vector<class ObjectFile::Atom*>&  Reader::getAtoms()
-{
-       return fEmptyAtomList;
-}
-
-
-
-const macho_nlist* Reader::binarySearchWithToc(const char* key, const char stringPool[], const macho_nlist symbols[], 
-                                                                                               const struct dylib_table_of_contents toc[], uint32_t symbolCount)
-{
-       int32_t high = symbolCount-1;
-       int32_t mid = symbolCount/2;
-               
-       for (int32_t low = 0; low <= high; mid = (low+high)/2) {
-               const uint32_t index = ENDIAN_READ32(toc[mid].symbol_index);
-               const macho_nlist* pivot = &symbols[index];
-               const char* pivotStr = &stringPool[pivot->n_strx()];
-               int cmp = strcmp(key, pivotStr);
-               if ( cmp == 0 )
-                       return pivot;
-               if ( cmp > 0 ) {
-                       // key > pivot 
-                       low = mid + 1;
-               }
-               else {
-                       // key < pivot 
-                       high = mid - 1;
-               }
-       }
-       return NULL;
-}
-
-
-const macho_nlist* Reader::binarySearch(const char* key, const char stringPool[], const macho_nlist symbols[], uint32_t symbolCount)
-{
-       const macho_nlist* base = symbols;
-       for (uint32_t n = symbolCount; n > 0; n /= 2) {
-               const macho_nlist* pivot = &base[n/2];
-               const char* pivotStr = &stringPool[pivot->n_strx()];
-               int cmp = strcmp(key, pivotStr);
-               if ( cmp == 0 )
-                       return pivot;
-               if ( cmp > 0 ) {
-                       // key > pivot 
-                       // move base to symbol after pivot
-                       base = &pivot[1];
-                       --n; 
-               }
-               else {
-                       // key < pivot 
-                       // keep same base
-               }
-       }
-       return NULL;
-}
-
-const macho_nlist* Reader::findExport(const char* name)
-{
-       if ( fDynamicInfo->tocoff() == 0 )
-               return binarySearch(name, fStrings, &fSymbols[fDynamicInfo->iextdefsym()], fDynamicInfo->nextdefsym());
-       else {
-               return binarySearchWithToc(name, fStrings, fSymbols, (dylib_table_of_contents*)((char*)fHeader + fDynamicInfo->tocoff()), 
-                                                               fDynamicInfo->nextdefsym());
-       }
-}
-
-bool Reader::hasExport(const char* name)
-{
-       return ( findExport(name) != NULL );
-}
-
-std::vector<class ObjectFile::Atom*>* Reader::getJustInTimeAtomsFor(const char* name)
-{
-       std::vector<class ObjectFile::Atom*>* atoms = NULL;
-       // search exports
-       if ( this->hasExport(name) ) {
-               // see if this atom already synthesized
-               ObjectFile::Atom* atom = NULL;
-               Mapper::iterator pos = fAtoms.find(name);
-               if ( pos != fAtoms.end() ) {
-                       atom = pos->second;
-               }
-               else {
-                       atom = new ExportAtom(*this, name);
-                       fAtoms[name] = atom;
-               }
-               // return a vector of one atom
-               atoms = new std::vector<class ObjectFile::Atom*>;
-               atoms->push_back(atom);
-               return atoms;
-       }
-       
-       // check re-exports
-       for (std::vector<Reader*>::iterator it = fReExportedDylibs.begin(); it != fReExportedDylibs.end(); it++) {
-               Reader* reExportedReader = *it;
-               atoms = reExportedReader->getJustInTimeAtomsFor(name);
-               if ( atoms != NULL )
-                       return atoms;
-       }
-       
-       return NULL;
-}
-
-
-std::vector<ObjectFile::StabsInfo>*    Reader::getStabsDebugInfo()
-{
-       return NULL;
-}
-
-const char*    Reader::getInstallPath()
-{
-       return fDylibID->name();
-}
-
-uint32_t Reader::getTimestamp()
-{
-       return fDylibID->timestamp();
-}
-
-uint32_t Reader::getCurrentVersion()
-{
-       return fDylibID->current_version();
-}
-
-uint32_t Reader::getCompatibilityVersion()
-{
-       return fDylibID->compatibility_version();
-}
-
-std::vector<const char*>* Reader::getDependentLibraryPaths()
-{
-       std::vector<const char*>* result = new std::vector<const char*>;
-       const uint32_t cmd_count = fHeader->ncmds();
-       const macho_load_command* const cmds = (macho_load_command*)((char*)fHeader + macho_header::size);
-       const macho_load_command* cmd = cmds;
-       for (uint32_t i = 0; i < cmd_count; ++i) {
-               switch (cmd->cmd()) {
-                       case LC_LOAD_DYLIB:
-                       case LC_LOAD_WEAK_DYLIB:
-                               {
-                                       result->push_back(((struct macho_dylib_command*)cmd)->name());
-                               }
-                               break;
-               }
-               cmd = (const macho_load_command*)(((char*)cmd)+cmd->cmdsize());
-       }
-       return result;
-}
-
-bool Reader::reExports(ObjectFile::Reader* child)
-{
-       // A dependent dylib is re-exported under two conditions:
-       //  1) parent contains LC_SUB_UMBRELLA or LC_SUB_LIBRARY with child name
-       {
-               const uint32_t cmd_count = fHeader->ncmds();
-               const macho_load_command* const cmds = (macho_load_command*)((char*)fHeader + macho_header::size);
-               const macho_load_command* cmd = cmds;
-               for (uint32_t i = 0; i < cmd_count; ++i) {
-                       switch (cmd->cmd()) {
-                               case LC_SUB_UMBRELLA:
-                                       {
-                                               const char* frameworkLeafName = ((macho_sub_umbrella_command*)cmd)->name();
-                                               const char* dylibName = child->getPath();
-                                               const char* lastSlash = strrchr(dylibName, '/');
-                                               if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], frameworkLeafName) == 0) )
-                                                       return true;
-                                       }
-                                       break;
-                               case LC_SUB_LIBRARY:
-                                       {
-                                               const char* dylibBaseName = ((macho_sub_library_command*)cmd)->name();
-                                               const char* dylibName = child->getPath();
-                                               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 )
-                                                       return true;
-                                       }
-                                       break;
-                       }
-                       cmd = (const macho_load_command*)(((char*)cmd)+cmd->cmdsize());
-               }
-       }
-       
-       //  2) child contains LC_SUB_FRAMEWORK with parent name 
-       {
-               const uint32_t cmd_count = ((Reader*)child)->fHeader->ncmds();
-               const macho_load_command* const cmds = (macho_load_command*)((char*)(((Reader*)child)->fHeader) + macho_header::size);
-               const macho_load_command* cmd = cmds;
-               for (uint32_t i = 0; i < cmd_count; ++i) {
-                       switch (cmd->cmd()) {
-                               case LC_SUB_FRAMEWORK:
-                                       {
-                                               const char* frameworkLeafName = ((macho_sub_framework_command*)cmd)->name();
-                                               const char* parentName = this->getPath();
-                                               const char* lastSlash = strrchr(parentName, '/');
-                                               if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], frameworkLeafName) == 0) )
-                                                       return true;
-                                       }
-                                       break;
-                       }
-                       cmd = (const macho_load_command*)(((char*)cmd)+cmd->cmdsize());
-               }
-       }
-       
-       
-       return false;
-}
-
-bool Reader::isDefinitionWeak(const ObjectFile::Atom& atom)
-{
-       const macho_nlist* sym = findExport(atom.getName());
-       if ( sym != NULL ) {
-               if ( (sym->n_desc() & N_WEAK_DEF) != 0 )
-                       return true;
-       }
-       return false;
-}
-
-
-
-Reader* MakeReader(const macho_header* mh, const char* path, const ObjectFile::ReaderOptions& options)
-{
-       return new Reader(mh, path, options);
-}
-
-
-
-};
-
-
-
-
-
-
-
diff --git a/src/Readers/ObjectFileMachO-all.cpp b/src/Readers/ObjectFileMachO-all.cpp
deleted file mode 100644 (file)
index 736b2a6..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
- */
-
-
-#include <sys/types.h>
-#include <sys/stat.h> 
-#include <sys/mman.h>
-#include <unistd.h> 
-#include <fcntl.h>
-#include <string.h>
-#include <math.h>
-#include <ar.h>
-
-#include <algorithm>
-#include <vector>
-#include <set>
-
-#include <mach-o/loader.h>
-#include <mach-o/nlist.h>
-#include <mach-o/reloc.h>
-#include <mach-o/ppc/reloc.h>
-#include <mach-o/ranlib.h>
-#include <mach-o/stab.h>
-
-#include "ObjectFile.h"
-#include "Options.h"
-
-
-
-
-// buiild Writer for -arch ppc64
-#undef MACHO_32_SAME_ENDIAN
-#undef MACHO_32_OPPOSITE_ENDIAN
-#undef MACHO_64_SAME_ENDIAN
-#undef MACHO_64_OPPOSITE_ENDIAN
-#if __ppc__ || __ppc64__
-       #define MACHO_64_SAME_ENDIAN
-#elif __i386__
-       #define MACHO_64_OPPOSITE_ENDIAN
-#else
-       #error unknown architecture
-#endif
-namespace ppc64 {
-       #undef  ARCH_PPC
-       #define ARCH_PPC64
-       #undef  ARCH_I386
-       #include "MachOAbstraction.h"
-       #include "ObjectFileMachO.cpp"
-       #include "ObjectFileDylibMachO.cpp"
-       #include "ObjectFileArchiveMachO.cpp"
-};
-
-// buiild Writer for -arch ppc
-#undef MACHO_32_SAME_ENDIAN
-#undef MACHO_32_OPPOSITE_ENDIAN
-#undef MACHO_64_SAME_ENDIAN
-#undef MACHO_64_OPPOSITE_ENDIAN
-#if __ppc__ || __ppc64__
-       #define MACHO_32_SAME_ENDIAN
-#elif __i386__
-       #define MACHO_32_OPPOSITE_ENDIAN
-#else
-       #error unknown architecture
-#endif
-namespace ppc {
-       #define ARCH_PPC
-       #undef  ARCH_PPC64
-       #undef  ARCH_I386
-       #include "MachOAbstraction.h"
-       #include "ObjectFileMachO.cpp"
-       #include "ObjectFileDylibMachO.cpp"
-       #include "ObjectFileArchiveMachO.cpp"
-};
-
-
-// buiild Writer for -arch i386
-#undef MACHO_32_SAME_ENDIAN
-#undef MACHO_32_OPPOSITE_ENDIAN
-#undef MACHO_64_SAME_ENDIAN
-#undef MACHO_64_OPPOSITE_ENDIAN
-#if __ppc__ || __ppc64__
-       #define MACHO_32_OPPOSITE_ENDIAN
-#elif __i386__
-       #define MACHO_32_SAME_ENDIAN
-#else
-       #error unknown architecture
-#endif
-#undef i386 // compiler sometimes #defines this
-namespace i386 {
-       #undef  ARCH_PPC
-       #undef  ARCH_PPC64
-       #define ARCH_I386
-       #include "MachOAbstraction.h"
-       #include "ObjectFileMachO.cpp"
-       #include "ObjectFileDylibMachO.cpp"
-       #include "ObjectFileArchiveMachO.cpp"
-};
-
-
diff --git a/src/Readers/ObjectFileMachO-all.h b/src/Readers/ObjectFileMachO-all.h
deleted file mode 100644 (file)
index 0f27244..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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 __OBJECTFILEMACHO__
-#define __OBJECTFILEMACHO__
-
-class Options;
-
-namespace ppc {
-       class macho_header;
-       namespace ObjectFileMachO {
-               extern class ObjectFile::Reader* MakeReader(const macho_header*, const char* path, const ObjectFile::ReaderOptions& options);
-       };
-       namespace ObjectFileDylibMachO {
-               extern class ObjectFile::Reader* MakeReader(const macho_header*, const char* path, const ObjectFile::ReaderOptions& options);
-       };
-       namespace ObjectFileArchiveMachO {
-               extern class ObjectFile::Reader* MakeReader(const uint8_t fileContent[], uint64_t fileLength, const char* path, const ObjectFile::ReaderOptions& options);
-       };
-};
-
-namespace ppc64 {
-       class macho_header;
-       namespace ObjectFileMachO {
-               extern class ObjectFile::Reader* MakeReader(const macho_header*, const char* path, const ObjectFile::ReaderOptions& options);
-       };
-       namespace ObjectFileDylibMachO {
-               extern class ObjectFile::Reader* MakeReader(const macho_header*, const char* path, const ObjectFile::ReaderOptions& options);
-       };
-       namespace ObjectFileArchiveMachO {
-               extern class ObjectFile::Reader* MakeReader(const uint8_t fileContent[], uint64_t fileLength, const char* path, const ObjectFile::ReaderOptions& options);
-       };
-};
-
-#undef i386 // compiler sometimes #defines this
-namespace i386 {
-       class macho_header;
-       namespace ObjectFileMachO {
-               extern class ObjectFile::Reader* MakeReader(const macho_header*, const char* path, const ObjectFile::ReaderOptions& options);
-       };
-       namespace ObjectFileDylibMachO {
-               extern class ObjectFile::Reader* MakeReader(const macho_header*, const char* path, const ObjectFile::ReaderOptions& options);
-       };
-       namespace ObjectFileArchiveMachO {
-               extern class ObjectFile::Reader* MakeReader(const uint8_t fileContent[], uint64_t fileLength, const char* path, const ObjectFile::ReaderOptions& options);
-       };
-};
-
-
-
-#endif // __OBJECTFILEMACHO__
-
-
-
diff --git a/src/Readers/ObjectFileMachO.cpp b/src/Readers/ObjectFileMachO.cpp
deleted file mode 100644 (file)
index 154ff8b..0000000
+++ /dev/null
@@ -1,2376 +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@
- */
-
-
-namespace ObjectFileMachO {
-
-class Reference : public ObjectFile::Reference
-{
-public:
-                                                       Reference(macho_uintptr_t fixUpOffset, Kind kind, const char* targetName, uint64_t offsetInTarget, uint64_t offsetInFromTarget);
-                                                       Reference(macho_uintptr_t fixUpOffset, Kind kind, class Atom& target, uint64_t offsetInTarget, uint64_t offsetInFromTarget);
-                                                       Reference(macho_uintptr_t fixUpOffset, Kind kind, class Atom& target, uint64_t offsetInTarget, class Atom& fromTarget, uint64_t offsetInFromTarget);
-       virtual                                 ~Reference();
-       
-       
-       virtual bool                    isTargetUnbound() const;
-       virtual bool                    isFromTargetUnbound() const;
-       virtual bool                    isWeakReference() const;
-       virtual bool                    requiresRuntimeFixUp(bool slideable) const;
-       virtual bool                    isLazyReference() const;
-       virtual Kind                    getKind() const;
-       virtual uint64_t                getFixUpOffset() const;
-       virtual const char*             getTargetName() const;
-       virtual ObjectFile::Atom& getTarget() const;
-       virtual uint64_t                getTargetOffset() const;
-       virtual bool                    hasFromTarget() const;
-       virtual ObjectFile::Atom& getFromTarget() const;
-       virtual const char*             getFromTargetName() const;
-       virtual void                    setTarget(ObjectFile::Atom&, uint64_t offset);
-       virtual void                    setFromTarget(ObjectFile::Atom&);
-       virtual void                    setFromTargetName(const char*);
-       virtual void                    setFromTargetOffset(uint64_t);
-       virtual const char*             getDescription() const;
-       virtual uint64_t                getFromTargetOffset() const;
-       
-       void                                    setLazy(bool);
-       void                                    setWeak(bool);
-private:
-       ObjectFile::Atom*               fTarget;
-       ObjectFile::Atom*               fFromTarget;
-       const char*                             fTargetName;
-       const char*                             fFromTargetName;
-       macho_uintptr_t                 fTargetOffset;
-       macho_uintptr_t                 fFromTargetOffset;
-       macho_uintptr_t                 fFixUpOffsetInSrc;
-       Kind                                    fKind;
-       bool                                    fLazy;
-       bool                                    fWeak;
-};
-
-
-
-class Reader : public ObjectFile::Reader 
-{
-public:
-                                                                                               Reader(const char* path);
-                                                                                               Reader(const macho_header* header, const char* path, const ObjectFile::ReaderOptions& options);
-       virtual                                                                         ~Reader();
-                                                                                               
-       virtual const char*                                                             getPath();
-       virtual std::vector<class ObjectFile::Atom*>&   getAtoms();
-       virtual std::vector<class ObjectFile::Atom*>*   getJustInTimeAtomsFor(const char* name);
-       virtual std::vector<ObjectFile::StabsInfo>*             getStabsDebugInfo(); // stabs info not associated with an atom
-
-
-private:
-       friend class Atom;
-       void                                                                            init(const macho_header* header, const char* path);
-       void                                                                            buildOffsetsSet(const macho_relocation_info* reloc, const macho_section* sect, std::set<uint32_t>& offsets, std::set<uint32_t>& dontUse);
-       void                                                                            addRelocReference(const macho_section* sect, const macho_relocation_info* reloc);
-       Atom*                                                                           findAtomCoveringOffset(uint32_t offset);
-       uint32_t                                                                        findAtomIndex(const Atom& atom);
-       void                                                                            addFixUp(uint32_t srcAddr, uint32_t dstAddr, Reference::Kind kind, uint32_t picBaseAddr);
-       class Segment*                                                          makeSegmentFromSection(const macho_section*);
-       macho_uintptr_t                                                         commonsOffset();
-       void                                                                            insertOffsetIfText(std::set<uint32_t>& offsets, uint32_t value);
-       void                                                                            insertOffsetIfNotText(std::set<uint32_t>& offsets, uint32_t value);
-       const macho_section*                                            findSectionCoveringOffset(uint32_t offset);
-       void                                                                            addCallSiteReference(Atom& src, uint32_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint32_t picBaseOffset, uint32_t offsetInTargetAtom);
-       void                                                                            deadStub(Atom& target);
-       
-       const char*                                                                     fPath;
-       const ObjectFile::ReaderOptions&                        fOptions;
-       const macho_header*                                                     fHeader;
-       const char*                                                                     fStrings;
-       const macho_nlist*                                                      fSymbols;
-       uint32_t                                                                        fSymbolCount;
-       const macho_segment_command*                            fSegment;
-       const uint32_t*                                                         fIndirectTable;
-       std::vector<class Atom*>                                        fAtoms;
-       std::vector<class Segment*>                                     fSegments;
-       std::set<class ObjectFile::Atom*>                       fDeadAtoms;
-       uint32_t                                                                        fNonAtomStabsStartIndex;
-       uint32_t                                                                        fNonAtomStabsCount;
-       std::vector<uint32_t>                                           fNonAtomExtras;
-};
-
-class Segment : public ObjectFile::Segment
-{
-public:
-       virtual const char*                     getName() const;
-       virtual bool                            isContentReadable() const;
-       virtual bool                            isContentWritable() const;
-       virtual bool                            isContentExecutable() const;
-protected:
-               Segment(const macho_section*);
-               friend class Reader;
-private:
-       const macho_section*            fSection;
-};
-
-class Atom : public ObjectFile::Atom
-{
-public:
-       virtual ObjectFile::Reader*                             getFile() const;
-       virtual const char*                                             getName() const;
-       virtual const char*                                             getDisplayName() const;
-       virtual Scope                                                   getScope() const;
-       virtual bool                                                    isTentativeDefinition() const;
-       virtual bool                                                    isWeakDefinition() const;
-       virtual bool                                                    isCoalesableByName() const;
-       virtual bool                                                    isCoalesableByValue() const;
-       virtual bool                                                    isZeroFill() const;
-       virtual bool                                                    dontDeadStrip() const;
-       virtual bool                                                    dontStripName() const;  // referenced dynamically
-       virtual bool                                                    isImportProxy() const;
-       virtual uint64_t                                                        getSize() const;
-       virtual std::vector<ObjectFile::Reference*>&  getReferences() const;
-       virtual bool                                                            mustRemainInSection() const;
-       virtual const char*                                                     getSectionName() const;
-       virtual Segment&                                                        getSegment() const;
-       virtual bool                                                            requiresFollowOnAtom() const;
-       virtual ObjectFile::Atom&                                       getFollowOnAtom() const;
-       virtual std::vector<ObjectFile::StabsInfo>*     getStabsDebugInfo() const;
-       virtual uint8_t                                                         getAlignment() const;
-       virtual WeakImportSetting                                       getImportWeakness() const { return ObjectFile::Atom::kWeakUnset; }
-       virtual void                                                            copyRawContent(uint8_t buffer[]) const;
-       virtual void                                                            writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-       virtual void                                                            setScope(Scope);
-       virtual void                                                            setImportWeakness(bool weakImport) { }
-
-       bool                                                                            isLazyStub();
-
-protected:
-       friend class Reader;
-                                                                                       Atom(Reader&, const macho_nlist*);
-                                                                                       Atom(Reader&, uint32_t offset);
-       virtual                                                                 ~Atom();
-       
-       const macho_section*                                    findSectionFromOffset(uint32_t offset);
-       const macho_section*                                    getCommonsSection();
-       void                                                                    setSize(macho_uintptr_t);
-       void                                                                    setFollowOnAtom(Atom&);
-       static bool                                                             atomCompare(const Atom* lhs, const Atom* rhs);
-       Reference*                                                              addDirectReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint64_t offsetInTarget, uint64_t offsetInFromTarget);
-       Reference*                                                              addByNameReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, const char* targetName, uint64_t offsetInTarget, uint64_t offsetInFromTarget);
-       Reference*                                                              addDifferenceReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint64_t offsetInTarget, Atom& fromTarget, uint64_t offsetInFromTarget);
-       Reference*                                                              addReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint64_t offsetInTarget, uint64_t offsetInFromTarget);
-       
-       Reader&                                                                 fOwner;
-       const macho_nlist*                                              fSymbol;
-       macho_uintptr_t                                                 fOffset;
-       macho_uintptr_t                                                 fSize;
-       const macho_section*                                    fSection;
-       Segment*                                                                fSegment;
-       const char*                                                             fSynthesizedName;
-       std::vector<class Reference*>                   fReferences;
-       ObjectFile::Atom::Scope                                 fScope;
-       uint32_t                                                                fStabsStartIndex;
-       uint32_t                                                                fStabsCount;
-       
-       static macho_section                                    fgCommonsSection;       // for us by tentative definitions
-};
-
-
-Reader* MakeReader(const macho_header* mh, const char* path, const ObjectFile::ReaderOptions& options)
-{      
-       return new Reader(mh, path, options);
-}
-
-
-Reader::Reader(const macho_header* header, const char* path, const ObjectFile::ReaderOptions& options)
- : fPath(NULL), fOptions(options), fHeader(NULL), fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fSegment(NULL)
-{
-       init(header, path);
-}
-
-Reader::Reader(const char* path)
- : fPath(NULL), fOptions(*(new ObjectFile::ReaderOptions())), fHeader(NULL), fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fSegment(NULL),
-       fIndirectTable(NULL), fNonAtomStabsStartIndex(0), fNonAtomStabsCount(0)
-{
-       struct stat stat_buf;
-       
-       int fd = ::open(path, O_RDONLY, 0);
-       ::fstat(fd, &stat_buf);
-       void* p = ::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE, fd, 0);
-       ::close(fd);
-       if ( ((macho_header*)p)->magic() == MH_MAGIC ) {
-               init((macho_header*)p, path);
-               return;
-       }
-       throw "add fat handling";
-}
-
-
-Reader::~Reader()
-{
-}
-
-
-bool Atom::atomCompare(const Atom* lhs, const Atom* rhs)
-{
-       return lhs->fOffset < rhs->fOffset;
-}
-
-
-
-void Reader::init(const macho_header* header, const char* path)
-{
-       // sanity check
-#if defined(ARCH_PPC)
-       if ( (header->magic() != MH_MAGIC) || (header->cputype() != CPU_TYPE_POWERPC) )
-               throw "not a valid ppc mach-o file";
-#elif defined(ARCH_I386)
-       if ( (header->magic() != MH_MAGIC) || (header->cputype() != CPU_TYPE_I386) )
-               throw "not a valid i386 mach-o file";
-#elif defined(ARCH_PPC64)
-       if ( (header->magic() != MH_MAGIC_64) || (header->cputype() != CPU_TYPE_POWERPC64) )
-               throw "not a valid ppc64 mach-o file";
-#endif
-
-       // cache intersting pointers
-       fPath = strdup(path);
-       fHeader = header;
-       const uint32_t cmd_count = header->ncmds();
-       const macho_load_command* const cmds = (macho_load_command*)((char*)header + macho_header::size);
-       const macho_load_command* cmd = cmds;
-       for (uint32_t i = 0; i < cmd_count; ++i) {
-               switch (cmd->cmd()) {
-                       case LC_SYMTAB:
-                               {
-                                       const macho_symtab_command* symtab = (macho_symtab_command*)cmd;
-                                       fSymbolCount = symtab->nsyms();
-                                       fSymbols = (const macho_nlist*)((char*)header + symtab->symoff());
-                                       fStrings = (char*)header + symtab->stroff();
-                               }
-                               break;
-                       case LC_DYSYMTAB:
-                               {
-                                       const macho_dysymtab_command* dsymtab = (struct macho_dysymtab_command*)cmd;
-                                       fIndirectTable = (uint32_t*)((char*)fHeader + dsymtab->indirectsymoff());
-                               }
-                               break;
-                       default:
-                               if ( cmd->cmd() == macho_segment_command::command ) {
-                                       fSegment= (macho_segment_command*)cmd;
-                               }
-                               break;
-               }
-               cmd = (const macho_load_command*)(((char*)cmd)+cmd->cmdsize());
-       }
-       
-       // add all atoms that have entries in symbol table
-       std::set<uint32_t> symbolAtomOffsets;
-       for (uint32_t i=0; i < fSymbolCount; ++i) {
-               const macho_nlist& sym = fSymbols[i];
-               if ( (sym.n_type() & N_STAB) == 0 ) {
-                       uint8_t type =  (sym.n_type() & N_TYPE);
-                       if ( (type == N_SECT) || ((type == N_UNDF) && (sym.n_value() != 0)) ) {
-                               // real definition or "tentative definition"
-                               Atom* newAtom = new Atom(*this, &sym);
-                               fAtoms.push_back(newAtom);
-                               symbolAtomOffsets.insert(newAtom->fOffset);
-                       }
-               }
-       }
-       
-       // add all points referenced in relocations
-       const macho_section* const sectionsStart = (macho_section*)((char*)fSegment + sizeof(macho_segment_command));
-       const macho_section* const sectionsEnd = &sectionsStart[fSegment->nsects()];
-       std::set<uint32_t> cleavePoints;
-       std::set<uint32_t> dontCleavePoints;
-       for (const macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
-               const macho_relocation_info* relocs = (macho_relocation_info*)((char*)(fHeader) + sect->reloff());
-               const uint32_t relocCount = sect->nreloc();
-               for (uint32_t r = 0; r < relocCount; ++r) {
-                       buildOffsetsSet(&relocs[r], sect, cleavePoints, dontCleavePoints);
-               }
-       }
-       // add all stub functions and (non)lazy pointers
-       std::set<uint32_t> deadStubOffsets;
-       for (const macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
-               uint8_t type (sect->flags() & SECTION_TYPE);
-               switch ( type ) {
-                       case S_SYMBOL_STUBS:
-                               {
-                                       const uint32_t stubSize = sect->reserved2();
-                                       // TVector glue sections are marked as S_SYMBOL_STUBS but are only 8 bytes
-                                       if ( stubSize > 8 ) {
-                                               for(uint32_t sectOffset=0; sectOffset < sect->size(); sectOffset += stubSize) {
-                                                       uint32_t stubAddr = sect->addr() + sectOffset;
-                                                       if ( cleavePoints.count(stubAddr) == 0 ) {
-                                                               cleavePoints.insert(stubAddr);
-                                                               deadStubOffsets.insert(stubAddr);
-                                                       }
-                                               }
-                                       }
-                               }
-                               break;
-                       case S_NON_LAZY_SYMBOL_POINTERS:
-                       case S_LAZY_SYMBOL_POINTERS:
-                               for(uint32_t sectOffset=0; sectOffset < sect->size(); sectOffset += sizeof(macho_uintptr_t)) {
-                                       uint32_t pointerAddr = sect->addr() + sectOffset;
-                                       cleavePoints.insert(pointerAddr);
-                               }
-                               break;
-               }
-               // also make sure each section break is a cleave point
-               if ( sect->size() != 0 ) 
-                       cleavePoints.insert(sect->addr());
-       }
-       
-       for (std::set<uint32_t>::iterator it=cleavePoints.begin(); it != cleavePoints.end(); it++) {
-               uint32_t cleavePoint = *it;
-               //printf("cleave offset 0x%08X, don't cleave=%d, isSymbol=%d\n", cleavePoint, dontCleavePoints.count(cleavePoint), symbolAtomOffsets.count(cleavePoint));
-               // only create an atom if it is not a don't-cleave point and there is not already an atom at this offset
-               if ( (dontCleavePoints.count(cleavePoint) == 0) && (symbolAtomOffsets.count(cleavePoint) == 0) )
-                       fAtoms.push_back(new Atom(*this, cleavePoint));
-       }
-       
-       const uint32_t atomCount = fAtoms.size();
-       if ( atomCount > 0 ) {
-               // sort the atoms so the occur in source file order
-               std::sort(fAtoms.begin(), fAtoms.end(), Atom::atomCompare);
-               
-               // tell each atom its size and follow on
-               const bool dontDeadStrip = ((fHeader->flags() & MH_SUBSECTIONS_VIA_SYMBOLS) == 0);
-               Atom* lastAtom = fAtoms[0];
-               for (uint32_t i=1; i < atomCount; ++i) {
-                       Atom* thisAtom = fAtoms[i];
-                       if ( lastAtom->getSize() == 0 ) {
-                               if ( lastAtom->fSection == thisAtom->fSection )
-                                       lastAtom->setSize(thisAtom->fOffset - lastAtom->fOffset);
-                               else
-                                       lastAtom->setSize(lastAtom->fSection->addr() + lastAtom->fSection->size() - lastAtom->fOffset);
-                       }
-                       if ( dontDeadStrip )
-                               lastAtom->setFollowOnAtom(*thisAtom);
-                       lastAtom = thisAtom;
-               }
-               lastAtom = fAtoms[atomCount-1];
-               if ( lastAtom->getSize() == 0 )
-                       lastAtom->setSize(lastAtom->fSection->addr() + lastAtom->fSection->size() - lastAtom->fOffset);
-               
-               // add relocation based references
-               for (const macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
-                       const macho_relocation_info* relocs = (macho_relocation_info*)((char*)(fHeader) + sect->reloff());
-                       const uint32_t relocCount = sect->nreloc();
-                       for (uint32_t r = 0; r < relocCount; ++r) {
-                               addRelocReference(sect, &relocs[r]);
-                       }
-               }               
-               
-               // add dead stubs to list to delete
-               for (std::set<uint32_t>::iterator it=deadStubOffsets.begin(); it != deadStubOffsets.end(); it++) {
-                       Atom* deadStub = findAtomCoveringOffset(*it);
-                       this->deadStub(*deadStub);
-               }
-               
-               // remove dead stubs and lazy pointers
-               for (std::set<ObjectFile::Atom*>::iterator deadIt=fDeadAtoms.begin(); deadIt != fDeadAtoms.end(); deadIt++) {
-                       for (std::vector<Atom*>::iterator it=fAtoms.begin(); it != fAtoms.end(); it++) {
-                               if ( *deadIt == *it ) {
-                                       fAtoms.erase(it);
-                                       break;
-                               }
-                       }
-               }
-
-       }
-
-       // process stabs debugging info
-       if ( ! fOptions.fStripDebugInfo ) {
-               // scan symbol table for stabs entries
-               fNonAtomStabsStartIndex = 0xFFFFFFFF;
-               fNonAtomStabsCount = 0;
-               uint32_t possibleStart = 0;
-               Atom* atom = NULL;
-               const uint32_t atomCount = fAtoms.size();
-               enum { start, inBeginEnd, foundFirst, inFunction } state = start;
-               for (uint32_t symbolIndex = 0; symbolIndex < fSymbolCount; ++symbolIndex ) {
-                       const macho_nlist* sym = &fSymbols[symbolIndex];
-                       uint8_t type = sym->n_type();
-                       if ( (type & N_STAB) != 0 ) {
-                               if ( fNonAtomStabsStartIndex == 0xFFFFFFFF )
-                                       fNonAtomStabsStartIndex = symbolIndex;
-                               switch (state) {
-                                       case start:
-                                               if ( (type == N_SLINE) || (type == N_SOL) ) {
-                                                       possibleStart = symbolIndex;
-                                                       state = foundFirst;
-                                               } 
-                                               else if ( type == N_BNSYM ) {
-                                                       macho_uintptr_t targetAddr = sym->n_value();
-                                                       atom = this->findAtomCoveringOffset(targetAddr);
-                                                       if ( (atom != NULL) || (atom->fOffset == targetAddr) ) {
-                                                               atom->fStabsStartIndex = symbolIndex;
-                                                               if ( fNonAtomStabsCount == 0 )
-                                                                       fNonAtomStabsCount = symbolIndex - fNonAtomStabsStartIndex;
-                                                       } 
-                                                       else {
-                                                               fprintf(stderr, "can't find atom for stabs 0x%02X at %08X in %s\n", type, targetAddr, path);
-                                                               atom = NULL;
-                                                       }
-                                                       state = inBeginEnd;
-                                               } 
-                                               else if ( (type == N_STSYM) || (type == N_LCSYM) ) {
-                                                       macho_uintptr_t targetAddr = sym->n_value();
-                                                       atom = this->findAtomCoveringOffset(targetAddr);
-                                                       if ( (atom != NULL) || (atom->fOffset == targetAddr) ) {
-                                                               atom->fStabsStartIndex = symbolIndex;
-                                                               atom->fStabsCount = 1;
-                                                               if ( fNonAtomStabsCount == 0 )
-                                                                       fNonAtomStabsCount = symbolIndex - fNonAtomStabsStartIndex;
-                                                       } 
-                                                       else {
-                                                               fprintf(stderr, "can't find atom for stabs 0x%02X at %08X in %s\n", type, targetAddr, path);
-                                                               atom = NULL;
-                                                       }
-                                               }
-                                               else if ( type == N_GSYM ) {
-                                                       // n_value field is NOT atom address ;-(
-                                                       // need to find atom by name match
-                                                       const char* symString = &fStrings[sym->n_strx()];
-                                                       const char* colon = strchr(symString, ':');
-                                                       bool found = false;
-                                                       if ( colon != NULL ) {
-                                                               int nameLen = colon - symString;
-                                                               for (uint32_t searchIndex = 0; searchIndex < atomCount; ++searchIndex) {
-                                                                       const char* atomName = fAtoms[searchIndex]->getName();
-                                                                       if ( (atomName != NULL) && (strncmp(&atomName[1], symString, nameLen) == 0) ) {
-                                                                               atom = fAtoms[searchIndex];
-                                                                               atom->fStabsStartIndex = symbolIndex;
-                                                                               atom->fStabsCount = 1;
-                                                                               if ( fNonAtomStabsCount == 0 )
-                                                                                       fNonAtomStabsCount = symbolIndex - fNonAtomStabsStartIndex;
-                                                                               found = true;
-                                                                               break;
-                                                                       }
-                                                               }
-                                                       }
-                                                       if ( !found ) {
-                                                               fprintf(stderr, "can't find atom for N_GSYM stabs %s in %s\n", symString, path);
-                                                               atom = NULL;
-                                                       }
-                                               }
-                                               else if ( type == N_LSYM ) {
-                                                       if ( fNonAtomStabsCount != 0 ) {
-                                                               // built with -gfull and some type definition not at start of source
-                                                               fNonAtomExtras.push_back(symbolIndex);
-                                                       }
-                                               }
-                                               break;
-                                       case inBeginEnd:
-                                               if ( type == N_ENSYM ) {
-                                                       state = start;
-                                                       if ( atom != NULL ) 
-                                                               atom->fStabsCount = symbolIndex - atom->fStabsStartIndex + 1;
-                                               }
-                                               break;
-                                       case foundFirst:
-                                               if ( (type == N_FUN) && (sym->n_sect() != 0) ) {
-                                                       state = inFunction;
-                                                       macho_uintptr_t targetAddr = sym->n_value();
-                                                       atom = this->findAtomCoveringOffset(targetAddr);
-                                                       if ( (atom == NULL) || (atom->fOffset != targetAddr) ) {
-                                                               fprintf(stderr, "can't find atom for stabs FUN index: %d at 0x%08llX in %s\n", symbolIndex, (uint64_t)targetAddr, path);
-                                                               atom = NULL;
-                                                       }
-                                                       else {
-                                                               atom->fStabsStartIndex = possibleStart;
-                                                               if ( fNonAtomStabsCount == 0 )
-                                                                       fNonAtomStabsCount = possibleStart - fNonAtomStabsStartIndex;
-                                                       } 
-                                               }
-                                               else if ( (type == N_FUN) && (sym->n_sect() == 0) ) {
-                                                       fprintf(stderr, "end stab FUN found without start FUN, index=%d in %s\n", symbolIndex, path);
-                                                       state = start;
-                                               }
-                                               break;
-                                       case inFunction:
-                                               if ( (type == N_FUN) && (sym->n_sect() == 0) ) {
-                                                       state = start;
-                                                       if ( atom != NULL ) 
-                                                               atom->fStabsCount = symbolIndex - atom->fStabsStartIndex + 1;
-                                               }
-                                               break;
-                               }
-                       }
-               }
-       
-       }
-}
-
-
-void Reader::addRelocReference(const macho_section* sect, const macho_relocation_info* reloc)
-{      
-       uint32_t srcAddr;
-       uint32_t dstAddr;
-       Atom* src;
-       Atom* dst;
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
-       uint32_t instruction;
-#endif
-       uint32_t* fixUpPtr;
-       if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
-               fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
-               const macho_relocation_info* nextReloc = &reloc[1];
-#endif
-               switch ( reloc->r_type() ) {
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
-                       case PPC_RELOC_BR24:
-                               {
-                                       if ( reloc->r_extern() ) {
-                                               instruction = OSSwapBigToHostInt32(*fixUpPtr);
-                                               int32_t displacement = (instruction & 0x03FFFFFC);
-                                               if ( (displacement & 0x02000000) != 0 )
-                                                       displacement |= 0xFC000000;
-                                               uint32_t offsetInTarget = sect->addr() + reloc->r_address() + displacement;
-                                               srcAddr = sect->addr() + reloc->r_address();
-                                               src = findAtomCoveringOffset(srcAddr);  
-                                               const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()];
-                                               const char* targetName = &fStrings[targetSymbol->n_strx()];
-                                               src->addByNameReference(srcAddr - src->fOffset, Reference::ppcFixupBranch24, targetName, offsetInTarget, 0);
-                                       }
-                                       else {
-                                               instruction = OSSwapBigToHostInt32(*fixUpPtr);
-                                               if ( (instruction & 0x4C000000) == 0x48000000 ) {
-                                                       int32_t displacement = (instruction & 0x03FFFFFC);
-                                                       if ( (displacement & 0x02000000) != 0 )
-                                                               displacement |= 0xFC000000;
-                                                       srcAddr = sect->addr() + reloc->r_address();
-                                                       dstAddr = srcAddr + displacement;
-                                                       src = findAtomCoveringOffset(srcAddr);
-                                                       dst = findAtomCoveringOffset(dstAddr);  
-                                                       this->addCallSiteReference(*src, srcAddr - src->fOffset, Reference::ppcFixupBranch24, *dst, 0, dstAddr - dst->fOffset);
-                                               }
-                                       }
-                               }
-                               break;
-                       case PPC_RELOC_BR14:
-                               {
-                                       if ( reloc->r_extern() ) {
-                                               srcAddr = sect->addr() + reloc->r_address();
-                                               src = findAtomCoveringOffset(srcAddr);  
-                                               const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()];
-                                               const char* targetName = &fStrings[targetSymbol->n_strx()];
-                                               src->addByNameReference(srcAddr - src->fOffset, Reference::ppcFixupBranch14, targetName, 0, 0);
-                                       }
-                                       else {
-                                               instruction = OSSwapBigToHostInt32(*fixUpPtr);
-                                               int32_t displacement = (instruction & 0x0000FFFC);
-                                               if ( (displacement & 0x00008000) != 0 )
-                                                       displacement |= 0xFFFF0000;
-                                               srcAddr = sect->addr() + reloc->r_address();
-                                               dstAddr = srcAddr + displacement;
-                                               src = findAtomCoveringOffset(srcAddr);
-                                               dst = findAtomCoveringOffset(dstAddr);  
-                                               this->addCallSiteReference(*src, srcAddr - src->fOffset, Reference::ppcFixupBranch14, *dst, 0, dstAddr - dst->fOffset);
-                                       }
-                               }
-                               break;
-                       case PPC_RELOC_PAIR:
-                               // skip, processed by a previous look ahead 
-                               break;
-                       case PPC_RELOC_LO16:
-                               {
-                                       if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
-                                               printf("PPC_RELOC_LO16 missing following pair\n");
-                                               break;
-                                       }
-                                       srcAddr = sect->addr() + reloc->r_address();
-                                       if ( reloc->r_extern() ) {
-                                               const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()];
-                                               const char* targetName = &fStrings[targetSymbol->n_strx()];
-                                               src = findAtomCoveringOffset(srcAddr);  
-                                               instruction = OSSwapBigToHostInt32(*fixUpPtr);
-                                               dstAddr = (nextReloc->r_address() << 16) | (instruction & 0x0000FFFF);
-                                               src->addByNameReference(srcAddr - src->fOffset, Reference::ppcFixupAbsLow16, targetName, dstAddr, 0);
-                                       }
-                                       else {
-                                               instruction = OSSwapBigToHostInt32(*fixUpPtr);
-                                               int16_t lowBits = (instruction & 0xFFFF);
-                                               dstAddr = (nextReloc->r_address() << 16) + (int32_t)lowBits;
-                                               if ( (lowBits & 0x8000) != 0 )
-                                                       dstAddr += 0x10000;
-                                               addFixUp(srcAddr, dstAddr, Reference::ppcFixupAbsLow16, 0);
-                                       }
-                               }
-                               break;
-                       case PPC_RELOC_LO14:
-                               {
-                                       if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
-                                               printf("PPC_RELOC_LO14 missing following pair\n");
-                                               break;
-                                       }
-                                       srcAddr = sect->addr() + reloc->r_address();
-                                       if ( reloc->r_extern() ) {
-                                               const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()];
-                                               const char* targetName = &fStrings[targetSymbol->n_strx()];
-                                               src = findAtomCoveringOffset(srcAddr);  
-                                               instruction = OSSwapBigToHostInt32(*fixUpPtr);
-                                               dstAddr = (nextReloc->r_address() << 16) | (instruction & 0x0000FFFC);
-                                               src->addByNameReference(srcAddr - src->fOffset, Reference::ppcFixupAbsLow14, targetName, dstAddr, 0);
-                                       }
-                                       else {
-                                               instruction = OSSwapBigToHostInt32(*fixUpPtr);
-                                               dstAddr = (nextReloc->r_address() << 16) | (instruction & 0x0000FFFC);
-                                               addFixUp(srcAddr, dstAddr, Reference::ppcFixupAbsLow14, 0);
-                                       }
-                               }
-                               break;
-                       case PPC_RELOC_HI16:
-                               {
-                                       if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
-                                               printf("PPC_RELOC_HI16 missing following pair\n");
-                                               break;
-                                       }
-                                       srcAddr = sect->addr() + reloc->r_address();
-                                       if ( reloc->r_extern() ) {
-                                               const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()];
-                                               const char* targetName = &fStrings[targetSymbol->n_strx()];
-                                               src = findAtomCoveringOffset(srcAddr);  
-                                               instruction = OSSwapBigToHostInt32(*fixUpPtr);
-                                               dstAddr = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF);
-                                               src->addByNameReference(srcAddr - src->fOffset, Reference::ppcFixupAbsHigh16, targetName, dstAddr, 0);
-                                       }
-                                       else {
-                                               instruction = OSSwapBigToHostInt32(*fixUpPtr);
-                                               dstAddr = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF);
-                                               addFixUp(srcAddr, dstAddr, Reference::ppcFixupAbsHigh16, 0);
-                                       }
-                               }
-                               break;
-                       case PPC_RELOC_HA16:
-                               {
-                                       if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
-                                               printf("PPC_RELOC_HA16 missing following pair\n");
-                                               break;
-                                       }
-                                       srcAddr = sect->addr() + reloc->r_address();
-                                       if ( reloc->r_extern() ) {
-                                               const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()];
-                                               const char* targetName = &fStrings[targetSymbol->n_strx()];
-                                               instruction = OSSwapBigToHostInt32(*fixUpPtr);
-                                               int16_t lowBits = (nextReloc->r_address() & 0x0000FFFF);
-                                               dstAddr = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
-                                               src = findAtomCoveringOffset(srcAddr);  
-                                               src->addByNameReference(srcAddr - src->fOffset, Reference::ppcFixupAbsHigh16AddLow, targetName, dstAddr, 0);
-                                       }
-                                       else {
-                                               instruction = OSSwapBigToHostInt32(*fixUpPtr);
-                                               int16_t lowBits = (nextReloc->r_address() & 0x0000FFFF);
-                                               dstAddr = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
-                                               addFixUp(srcAddr, dstAddr, Reference::ppcFixupAbsHigh16AddLow, 0);
-                                       }
-                               }
-                               break;
-                       case GENERIC_RELOC_VANILLA:
-                               {
-                                       srcAddr = sect->addr() + reloc->r_address();
-                                       Atom* srcAtom = findAtomCoveringOffset(srcAddr);
-                                       uint32_t offsetInSrcAtom = srcAddr - srcAtom->fOffset;
-                                       macho_uintptr_t pointerValue = ENDIAN_SWAP_POINTER(*((macho_uintptr_t*)fixUpPtr));
-                                       if ( reloc->r_extern() ) {
-                                               const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()];
-                                               uint8_t type = targetSymbol->n_type() & N_TYPE;
-                                               if ( type == N_UNDF ) {
-                                                       const char* targetName = &fStrings[targetSymbol->n_strx()];
-                                                       macho_uintptr_t addend = pointerValue;
-                                                       // ppc lazy pointers have initial reference to dyld_stub_binding_helper
-                                                       if ( (srcAtom->fSection->flags() & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS ) {
-                                                               std::vector<ObjectFile::Reference*>&  refs = srcAtom->getReferences();
-                                                               if ( refs.size() > 0 ) {
-                                                                       Reference* ref = (Reference*)refs[0];
-               #if defined(ARCH_PPC64)
-                                                                        // hack to work around bad crt1.o in Mac OS X 10.4
-                                                                       targetName = "dyld_stub_binding_helper";
-               #endif
-                                                                       ref->setFromTargetName(targetName);
-                                                               }
-                                                               else {
-                                                                       fprintf(stderr, "lazy pointer (%s) should only have one reference - has %ld references\n", srcAtom->getDisplayName(), refs.size());
-                                                               }
-                                                       } 
-               #if defined(ARCH_PPC64)
-                                                       // hack to work around bad crt1.o in Mac OS X 10.4
-                                                       else if ( (srcAtom->fSection->flags() & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS ) {
-                                                               // ignore extra relocation
-                                                       }
-               #endif
-                                                       else {
-                                                               srcAtom->addByNameReference(offsetInSrcAtom, Reference::pointer, targetName, addend, 0);
-                                                       }
-                                               }
-                                               else {
-                                                       dstAddr = targetSymbol->n_value();
-                                                       Atom* dstAtom = findAtomCoveringOffset(dstAddr);
-                                                       macho_uintptr_t addend = pointerValue;
-                                                       // ppc lazy pointers have initial reference to dyld_stub_binding_helper
-                                                       if ( (srcAtom->fSection->flags() & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS ) {
-                                                               std::vector<ObjectFile::Reference*>&  refs = srcAtom->getReferences();
-                                                               if ( refs.size() > 0 ) {
-                                                                       Reference* ref = (Reference*)refs[0];
-                                                                       ref->setFromTarget(*dstAtom);
-                                                                       ref->setFromTargetOffset(dstAddr - dstAtom->fOffset);
-                                                               }
-                                                               else {
-                                                                       fprintf(stderr, "lazy pointer (%s) should only have one reference - has %ld references\n", srcAtom->getDisplayName(), refs.size());
-                                                               }
-                                                       } 
-                                                       else {
-                                                               srcAtom->addReference(offsetInSrcAtom, Reference::pointer, *dstAtom, addend, 0);
-                                                       }
-                                               }
-                                       }
-                                       else {
-                                               Atom* dstAtom = findAtomCoveringOffset(pointerValue);
-                                               // lazy pointers have references to dyld_stub_binding_helper which need to be ignored
-                                               if ( (srcAtom->fSection->flags() & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS ) {
-                                                       std::vector<ObjectFile::Reference*>&  refs = srcAtom->getReferences();
-                                                       if ( refs.size() > 0 ) {
-                                                               Reference* ref = (Reference*)refs[0];
-                                                               ref->setFromTarget(*dstAtom);
-                                                               ref->setFromTargetOffset(pointerValue - dstAtom->fOffset);
-                                                       }
-                                                       else {
-                                                               fprintf(stderr, "lazy pointer (%s) should only have one reference - has %ld references\n", srcAtom->getDisplayName(), refs.size());
-                                                       }
-                                               }
-                                               else {
-                                                       srcAtom->addReference(offsetInSrcAtom, Reference::pointer, *dstAtom, pointerValue-dstAtom->fOffset, 0);
-                                               }
-                                       }
-                               }
-                               break;
-                       case PPC_RELOC_JBSR:
-                               // ignore for now
-                               break;
-#endif
-#if defined(ARCH_I386)
-                       case GENERIC_RELOC_VANILLA:
-                               {
-                                       srcAddr = sect->addr() + reloc->r_address();
-                                       src = findAtomCoveringOffset(srcAddr);
-                                       if ( reloc->r_length() != 2 )
-                                               throw "bad vanilla relocation length";
-                                       Reference::Kind kind;
-                                       macho_uintptr_t pointerValue = ENDIAN_SWAP_POINTER(*((macho_uintptr_t*)fixUpPtr));
-                                       if ( reloc->r_pcrel() ) {
-                                               kind = Reference::x86FixupBranch32;
-                                               pointerValue += srcAddr + sizeof(macho_uintptr_t);
-                                       }
-                                       else {
-                                               kind = Reference::pointer;
-                                       }
-                                       uint32_t offsetInSrcAtom = srcAddr - src->fOffset;
-                                       if ( reloc->r_extern() ) {
-                                               const macho_nlist* targetSymbol = &fSymbols[reloc->r_symbolnum()];
-                                               uint8_t type = targetSymbol->n_type() & N_TYPE;
-                                               if ( type == N_UNDF ) {
-                                                       const char* targetName = &fStrings[targetSymbol->n_strx()];
-                                                       macho_uintptr_t addend = pointerValue;
-                                                       src->addByNameReference(offsetInSrcAtom, kind, targetName, addend, 0);
-                                               }
-                                               else {
-                                                       dstAddr = targetSymbol->n_value();
-                                                       dst = findAtomCoveringOffset(dstAddr);
-                                                       macho_uintptr_t addend = pointerValue - dstAddr;
-                                                       src->addReference(offsetInSrcAtom, kind, *dst, addend, 0);
-                                               }
-                                       }
-                                       else {
-                                               dst = findAtomCoveringOffset(pointerValue);     
-                                               // lazy pointers have references to dyld_stub_binding_helper which need to be ignored
-                                               if ( (src->fSection->flags() & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS ) {
-                                                       std::vector<ObjectFile::Reference*>&  refs = src->getReferences();
-                                                       if ( refs.size() == 1 ) {
-                                                               Reference* ref = (Reference*)refs[0];
-                                                               ref->setFromTarget(*dst);
-                                                               ref->setFromTargetOffset(pointerValue - dst->fOffset);
-                                                       }
-                                                       else {
-                                                               fprintf(stderr, "lazy pointer (%s) should only have one reference - has %ld references\n", src->getDisplayName(), refs.size());
-                                                       }
-                                               }
-                                               else if ( ((uint8_t*)fixUpPtr)[-1] == 0xE8 )  // special case call instruction
-                                                       this->addCallSiteReference(*src, offsetInSrcAtom, kind, *dst, 0, pointerValue - dst->fOffset);
-                                               else
-                                                       src->addReference(offsetInSrcAtom, kind, *dst, 0, 0);
-                                       }
-                               }
-                               break;
-#endif
-
-                       default:
-                               printf("unknown relocation type %d\n", reloc->r_type());
-               }
-       }
-       else {
-               const macho_scattered_relocation_info* sreloc = (macho_scattered_relocation_info*)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* nextSReloc = &sreloc[1];
-               const macho_relocation_info* 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();
-                       }
-               }
-               else {
-                       if ( nextSReloc->r_type() == PPC_RELOC_PAIR ) {
-                               nextRelocIsPair = true;
-                               nextRelocAddress = nextSReloc->r_address();
-                               nextRelocValue = nextSReloc->r_value();
-                       }
-               }
-               switch (sreloc->r_type()) {
-                       case GENERIC_RELOC_VANILLA:
-                               {
-                                       macho_uintptr_t betterDstAddr = ENDIAN_SWAP_POINTER(*((macho_uintptr_t*)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)
-                                       Atom* src = findAtomCoveringOffset(srcAddr);
-                                       Atom* dst = findAtomCoveringOffset(dstAddr);
-                                       src->addReference(srcAddr - src->fOffset, Reference::pointer, *dst, betterDstAddr - dst->fOffset, 0);
-                               }
-                               break;
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
-                       case PPC_RELOC_BR24:
-                               {
-                                       instruction = OSSwapBigToHostInt32(*fixUpPtr);
-                                       if ( (instruction & 0x4C000000) == 0x48000000 ) {
-                                               int32_t displacement = (instruction & 0x03FFFFFC);
-                                               if ( (displacement & 0x02000000) != 0 )
-                                                       displacement |= 0xFC000000;
-                                               srcAddr = sect->addr() + sreloc->r_address();
-                                               dstAddr = sreloc->r_value();
-                                               src = findAtomCoveringOffset(srcAddr);
-                                               dst = findAtomCoveringOffset(dstAddr);  
-                                               this->addCallSiteReference(*src, srcAddr - src->fOffset, Reference::ppcFixupBranch24, *dst, 0, srcAddr + displacement - sreloc->r_value());
-                                       }
-                               }
-                               break;
-                       case PPC_RELOC_LO16_SECTDIFF:
-                               {
-                                       if ( ! nextRelocIsPair) {
-                                               printf("PPC_RELOC_LO16_SECTDIFF missing following PAIR\n");
-                                               break;
-                                       }
-                                       src = findAtomCoveringOffset(srcAddr);  
-                                       dst = findAtomCoveringOffset(dstAddr);  
-                                       instruction = OSSwapBigToHostInt32(*fixUpPtr);
-                                       int16_t lowBits = (instruction & 0xFFFF);
-                                       int32_t displacement = (nextRelocAddress << 16) + (int32_t)lowBits;
-                                       if ( (lowBits & 0x8000) != 0 )
-                                               displacement += 0x10000;
-                                       uint32_t picBaseOffset = nextRelocValue - src->fOffset;
-                                       int64_t dstOffset = src->fOffset + picBaseOffset + displacement - dst->fOffset;
-                                       src->addReference(srcAddr - src->fOffset, Reference::ppcFixupPicBaseLow16, *dst, dstOffset, picBaseOffset);
-                               }
-                               break;
-                       case PPC_RELOC_LO14_SECTDIFF:
-                               {
-                                       if ( ! nextRelocIsPair) {
-                                               printf("PPC_RELOC_LO14_SECTDIFF missing following PAIR\n");
-                                               break;
-                                       }
-                                       src = findAtomCoveringOffset(srcAddr);  
-                                       dst = findAtomCoveringOffset(dstAddr);  
-                                       instruction = OSSwapBigToHostInt32(*fixUpPtr);
-                                       int16_t lowBits = (instruction & 0xFFFC);
-                                       int32_t displacement = (nextRelocAddress << 16) + (int32_t)lowBits;
-                                       if ( (lowBits & 0x8000) != 0 )
-                                               displacement += 0x10000;
-                                       uint32_t picBaseOffset = nextRelocValue - src->fOffset;
-                                       int64_t dstOffset = src->fOffset + picBaseOffset + displacement - dst->fOffset;
-                                       src->addReference(srcAddr - src->fOffset, Reference::ppcFixupPicBaseLow14, *dst, dstOffset, picBaseOffset);
-                               }
-                               break;
-                       case PPC_RELOC_HA16_SECTDIFF:
-                               {
-                                       if ( ! nextRelocIsPair) {
-                                               printf("PPC_RELOC_LO14_SECTDIFF missing following PAIR\n");
-                                               break;
-                                       }
-                                       src = findAtomCoveringOffset(srcAddr);  
-                                       dst = findAtomCoveringOffset(dstAddr);  
-                                       instruction = OSSwapBigToHostInt32(*fixUpPtr);
-                                       int16_t lowBits = (nextRelocAddress & 0x0000FFFF);
-                                       int32_t displacement = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
-                                       uint32_t picBaseOffset = nextRelocValue - src->fOffset;
-                                       int64_t dstOffset = src->fOffset + picBaseOffset + displacement - dst->fOffset;
-                                       src->addReference(srcAddr - src->fOffset, Reference::ppcFixupPicBaseHigh16, *dst, dstOffset, picBaseOffset);
-                               }
-                               break;
-                       case PPC_RELOC_LO14:
-                               {
-                                       if ( ! nextRelocIsPair) {
-                                               printf("PPC_RELOC_LO14 missing following PAIR\n");
-                                               break;
-                                       }
-                                       src = findAtomCoveringOffset(srcAddr);  
-                                       dst = findAtomCoveringOffset(dstAddr);  
-                                       instruction = OSSwapBigToHostInt32(*fixUpPtr);
-                                       int16_t lowBits = (instruction & 0xFFFC);
-                                       uint32_t betterDstAddr = (nextRelocAddress << 16) + (int32_t)lowBits;
-                                       if ( (lowBits & 0x8000) != 0 )
-                                               betterDstAddr += 0x10000;
-                                       src->addReference(srcAddr - src->fOffset, Reference::ppcFixupAbsLow14, *dst, betterDstAddr - dst->fOffset, 0);
-                               }
-                               break;
-                       case PPC_RELOC_LO16:
-                               {
-                                       if ( ! nextRelocIsPair) {
-                                               printf("PPC_RELOC_LO16 missing following PAIR\n");
-                                               break;
-                                       }
-                                       src = findAtomCoveringOffset(srcAddr);  
-                                       dst = findAtomCoveringOffset(dstAddr);  
-                                       instruction = OSSwapBigToHostInt32(*fixUpPtr);
-                                       int16_t lowBits = (instruction & 0xFFFF);
-                                       uint32_t betterDstAddr = (nextRelocAddress << 16) + (int32_t)lowBits;
-                                       if ( (lowBits & 0x8000) != 0 )
-                                               betterDstAddr += 0x10000;
-                                       src->addReference(srcAddr - src->fOffset, Reference::ppcFixupAbsLow16, *dst, betterDstAddr - dst->fOffset, 0);
-                               }
-                               break;
-                       case PPC_RELOC_HA16:
-                               {
-                                       if ( ! nextRelocIsPair) {
-                                               printf("PPC_RELOC_HA16 missing following PAIR\n");
-                                               break;
-                                       }
-                                       src = findAtomCoveringOffset(srcAddr);  
-                                       dst = findAtomCoveringOffset(dstAddr);  
-                                       instruction = OSSwapBigToHostInt32(*fixUpPtr);
-                                       int16_t lowBits = (nextRelocAddress & 0xFFFF);
-                                       uint32_t betterDstAddr = ((instruction & 0xFFFF) << 16) + (int32_t)lowBits;
-                                       src->addReference(srcAddr - src->fOffset, Reference::ppcFixupAbsHigh16AddLow, *dst, betterDstAddr - dst->fOffset, 0);
-                               }
-                               break;
-                       case PPC_RELOC_SECTDIFF:
-                       case PPC_RELOC_LOCAL_SECTDIFF:
-                               {
-                                       const macho_scattered_relocation_info* nextReloc = &sreloc[1];
-                                       if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
-                                               printf("PPC_RELOC_SECTDIFF missing following pair\n");
-                                               break;
-                                       }
-                                       srcAddr = sect->addr() + sreloc->r_address();
-                                       uint32_t toAddr = sreloc->r_value();
-                                       uint32_t fromAddr = nextReloc->r_value();
-                                       src = findAtomCoveringOffset(srcAddr);  
-                                       Atom* to = findAtomCoveringOffset(toAddr);      
-                                       Atom* from = findAtomCoveringOffset(fromAddr);  
-                                       //macho_intptr_t pointerValue = *(macho_intptr_t*)fixUpPtr;
-                                       //uint64_t toOffset = to->fOffset;
-                                       //uint64_t fromOffset = from->fOffset;
-                                       //int64_t pointerValue64 = pointerValue;
-                                       //uint64_t addend = pointerValue64 - (toOffset - fromOffset);
-                                       Reference::Kind kind = Reference::pointer32Difference;
-                                       if ( sreloc->r_length() == 3 )
-                                               kind =  Reference::pointer64Difference;
-                                       src->addDifferenceReference(srcAddr - src->fOffset, kind, *to, toAddr - to->fOffset, *from, fromAddr - from->fOffset);
-                               }
-                               break;
-                       case PPC_RELOC_PAIR:
-                               break;
-                       case PPC_RELOC_HI16_SECTDIFF:
-                               printf("unexpected scattered relocation type PPC_RELOC_HI16_SECTDIFF\n");
-                               break;
-#endif
-#if defined(ARCH_I386)
-                       case GENERIC_RELOC_SECTDIFF:
-                       case GENERIC_RELOC_LOCAL_SECTDIFF:
-                               {
-                                       if ( nextSReloc->r_type() != GENERIC_RELOC_PAIR ) {
-                                               printf("GENERIC_RELOC_SECTDIFF missing following pair\n");
-                                               break;
-                                       }
-                                       srcAddr = sect->addr() + sreloc->r_address();
-                                       uint32_t toAddr = sreloc->r_value();
-                                       uint32_t fromAddr = nextSReloc->r_value();
-                                       src = findAtomCoveringOffset(srcAddr);  
-                                       Atom* to = findAtomCoveringOffset(toAddr);      
-                                       Atom* from = findAtomCoveringOffset(fromAddr);  
-                                       Reference::Kind kind = Reference::pointer32Difference;
-                                       if ( sreloc->r_length() != 2 )
-                                               throw "bad length for GENERIC_RELOC_SECTDIFF";
-                                       src->addDifferenceReference(srcAddr - src->fOffset, kind, *to, toAddr - to->fOffset, *from, fromAddr - from->fOffset);
-                               }
-                               break;
-                       case GENERIC_RELOC_PAIR:
-                               // do nothing, already used via a look ahead
-                               break;
-#endif
-                       default:
-                               printf("unknown scattered relocation type %d\n", sreloc->r_type());
-               }
-               
-       }
-}
-
-
-void Reader::addFixUp(uint32_t srcAddr, uint32_t dstAddr, Reference::Kind kind, uint32_t picBaseAddr)
-{
-       Atom* src = findAtomCoveringOffset(srcAddr);    
-       Atom* dst = findAtomCoveringOffset(dstAddr);    
-       src->addReference(srcAddr - src->fOffset, kind, *dst, dstAddr - dst->fOffset, picBaseAddr - src->fOffset);
-}
-
-Atom* Reader::findAtomCoveringOffset(uint32_t offset)
-{
-#if 1
-       // binary search of sorted atoms
-       Atom** base = &fAtoms[0];
-       for (uint32_t n = fAtoms.size(); n > 0; n /= 2) {
-               Atom** pivot = &base[n/2];
-               Atom* pivotAtom = *pivot;
-               if ( pivotAtom->fOffset <= offset ) {
-                       if ( offset < (pivotAtom->fOffset + pivotAtom->fSize) )
-                               return pivotAtom;
-                       // key > pivot 
-                       // move base to symbol after pivot
-                       base = &pivot[1];
-                       --n; 
-               }
-               else {
-                       // key < pivot 
-                       // keep same base
-               }
-       }
-       // possible that last atom is zero length
-       Atom* lastAtom = fAtoms.back();
-       if ( (lastAtom->fOffset == offset) && (lastAtom->fSize == 0) )
-               return lastAtom;
-#else
-       const uint32_t atomCount = fAtoms.size();
-       for (uint32_t i=0; i < atomCount; ++i) {
-               Atom* atom = fAtoms[i];
-               if ( (atom->fOffset <= offset) && (offset < (atom->fOffset + atom->fSize)) )
-                       return atom;
-       }
-#endif
-       throwf("address 0x%08X is not in any atom", offset);
-}
-
-uint32_t Reader::findAtomIndex(const Atom& atom)
-{
-       const Atom* target = &atom;
-       const uint32_t atomCount = fAtoms.size();
-       for (uint32_t i=0; i < atomCount; ++i) {
-               Atom* anAtom = fAtoms[i];
-               if ( anAtom == target )
-                       return i;
-       }
-       return 0xffffffff;
-}
-
-static void insertOffset(std::set<uint32_t>& offsets, uint32_t value)
-{
-       //fprintf(stderr, "cleave point at 0x%08X\n", value);
-       offsets.insert(value);
-}
-
-void Reader::insertOffsetIfNotText(std::set<uint32_t>& offsets, uint32_t value)
-{
-       const macho_section* sect = findSectionCoveringOffset(value);
-       if ( (sect == NULL) || (strcmp(sect->segname(),"__TEXT") != 0) || (strncmp(sect->sectname(),"__text", 6) != 0) ) {
-               offsets.insert(value);
-       }
-}
-
-void Reader::insertOffsetIfText(std::set<uint32_t>& offsets, uint32_t value)
-{
-       const macho_section* sect = findSectionCoveringOffset(value);
-       if ( (sect != NULL) && (strcmp(sect->segname(),"__TEXT") == 0) && (strncmp(sect->sectname(),"__text", 6) == 0) ) {
-               //fprintf(stderr, "don't cleave point at 0x%08X\n", value);
-               offsets.insert(value);
-       }
-}
-
-const macho_section* Reader::findSectionCoveringOffset(uint32_t offset)
-{
-       const macho_section* const sectionsStart = (macho_section*)((char*)fSegment + sizeof(macho_segment_command));
-       const macho_section* const sectionsEnd = &sectionsStart[fSegment->nsects()];
-       for (const macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
-               if ( (sect->addr() <= offset) && (offset < (sect->addr() + sect->size())) )
-                       return sect;
-       }
-       return NULL;
-}
-
-
-void Reader::buildOffsetsSet(const macho_relocation_info* reloc, const macho_section* sect, std::set<uint32_t>& cleavePoints, std::set<uint32_t>& dontCleavePoints)
-{
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
-       uint32_t targetAddr;
-#endif
-       if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
-               uint32_t* fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
-               uint32_t instruction;
-#endif
-               switch ( reloc->r_type() ) {
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
-                       case PPC_RELOC_BR14:
-                               // do nothing. local branch should not cleave
-                               break;
-                       case PPC_RELOC_BR24:
-                               {
-                                       if ( ! reloc->r_extern() ) {
-                                               instruction = OSSwapBigToHostInt32(*fixUpPtr);
-                                               if ( (instruction & 0x4C000000) == 0x48000000 ) {
-                                                       int32_t displacement = (instruction & 0x03FFFFFC);
-                                                       if ( (displacement & 0x02000000) != 0 )
-                                                               displacement |= 0xFC000000;
-                                                       //cleavePoints.insert(reloc->r_address() + displacement);
-                                                       insertOffset(cleavePoints, sect->addr() + reloc->r_address() + displacement);
-                                               }
-                                       }
-                               }
-                               break;
-                       case PPC_RELOC_PAIR:
-                               // skip, processed by a look ahead 
-                               break;
-                       case PPC_RELOC_LO16:
-                               {
-                                       const macho_relocation_info* nextReloc = &reloc[1];
-                                       if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
-                                               printf("PPC_RELOC_LO16 missing following pair\n");
-                                               break;
-                                       }
-                                       if ( ! reloc->r_extern() ) {
-                                               instruction = OSSwapBigToHostInt32(*fixUpPtr);
-                                               targetAddr = (nextReloc->r_address() << 16) | (instruction & 0x0000FFFF);
-                                               //cleavePoints.insert(targetAddr);
-                                               insertOffset(cleavePoints, (targetAddr));
-                                       }
-                               }
-                               break;
-                       case PPC_RELOC_LO14:
-                               {
-                                       const macho_relocation_info* nextReloc = &reloc[1];
-                                       if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
-                                               printf("PPC_RELOC_LO14 missing following pair\n");
-                                               break;
-                                       }
-                                       if ( ! reloc->r_extern() ) {
-                                               instruction = OSSwapBigToHostInt32(*fixUpPtr);
-                                               targetAddr = (nextReloc->r_address() << 16) | (instruction & 0x0000FFFC);
-                                               //cleavePoints.insert(targetAddr);
-                                               insertOffset(cleavePoints, (targetAddr));
-                                       }
-                               }
-                               break;
-                       case PPC_RELOC_HI16:
-                               {
-                                       const macho_relocation_info* nextReloc = &reloc[1];
-                                       if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
-                                               printf("PPC_RELOC_HI16 missing following pair\n");
-                                               break;
-                                       }
-                                       if ( ! reloc->r_extern() ) {
-                                               instruction = OSSwapBigToHostInt32(*fixUpPtr);
-                                               targetAddr = ((instruction & 0x0000FFFF) << 16) | (nextReloc->r_address() & 0x0000FFFF);
-                                               //cleavePoints.insert(targetAddr);
-                                               insertOffset(cleavePoints, targetAddr);
-                                       }
-                               }
-                               break;
-                       case PPC_RELOC_HA16:
-                               {
-                                       const macho_relocation_info* nextReloc = &reloc[1];
-                                       if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
-                                               printf("PPC_RELOC_HA16 missing following pair\n");
-                                               break;
-                                       }
-                                       if ( ! reloc->r_extern() ) {
-                                               instruction = OSSwapBigToHostInt32(*fixUpPtr);
-                                               int16_t lowBits = (nextReloc->r_address() & 0x0000FFFF);
-                                               targetAddr = ((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits;
-                                               //cleavePoints.insert(targetAddr);
-                                               insertOffset(cleavePoints, targetAddr);
-                                       }
-                               }
-                               break;
-                       case PPC_RELOC_JBSR:
-                               // ignore for now
-                               break;
-#endif
-                       case GENERIC_RELOC_VANILLA:
-                               {
-#if defined(ARCH_PPC64)
-                                       if  ( reloc->r_length() != 3 )
-                                               throw "vanilla pointer relocation found that is not 8-bytes";
-#elif defined(ARCH_PPC) || defined(ARCH_I386)
-                                       if  ( reloc->r_length() != 2 )
-                                               throw "vanilla pointer relocation found that is not 4-bytes";
-#endif
-                                       //fprintf(stderr, "addr=0x%08X, pcrel=%d, len=%d, extern=%d, type=%d\n", reloc->r_address(), reloc->r_pcrel(), reloc->r_length(), reloc->r_extern(), reloc->r_type());
-                                       if ( !reloc->r_extern() ) {
-                                               macho_uintptr_t pointerValue = ENDIAN_SWAP_POINTER(*((macho_uintptr_t*)fixUpPtr));
-#if defined(ARCH_I386)
-                                       // i386 stubs have internal relocs that should not cause a cleave
-                                       if ( (sect->flags() & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS )
-                                               break;
-#endif
-                                               if ( reloc->r_pcrel() )
-                                                       pointerValue += reloc->r_address() + sect->addr() + sizeof(macho_uintptr_t);
-                                               // a pointer into code does not cleave the code (gcc always pointers to labels)
-                                               insertOffsetIfNotText(cleavePoints, pointerValue);
-                                       }
-                               }
-                               break;
-                       default:
-                               printf("unknown relocation type %d\n", reloc->r_type());
-               }
-       }
-       else {
-               const macho_scattered_relocation_info* sreloc = (macho_scattered_relocation_info*)reloc;
-               switch (sreloc->r_type()) {
-                       case GENERIC_RELOC_VANILLA:
-                               insertOffset(cleavePoints, sreloc->r_value());
-                               break;
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
-                       case PPC_RELOC_BR24:
-                               insertOffset(cleavePoints, sreloc->r_value());
-                               break;
-                       case PPC_RELOC_HA16:
-                       case PPC_RELOC_HI16:
-                       case PPC_RELOC_LO16:
-                       case PPC_RELOC_LO14:
-                       case PPC_RELOC_LO16_SECTDIFF:
-                       case PPC_RELOC_LO14_SECTDIFF:
-                       case PPC_RELOC_HA16_SECTDIFF:
-                       case PPC_RELOC_HI16_SECTDIFF:
-                               //cleavePoints.insert(sreloc->r_value());
-                               insertOffset(cleavePoints, sreloc->r_value());
-                               insertOffsetIfText(dontCleavePoints, sreloc->r_value());
-                               break;
-                       case PPC_RELOC_SECTDIFF:
-                       case PPC_RELOC_LOCAL_SECTDIFF:
-                               // these do not cleave up a .o file
-                               // a SECTDIFF in __TEXT probably means a jump table, and should prevent a cleave
-                               {
-                                       const macho_scattered_relocation_info* nextReloc = &sreloc[1];
-                                       if ( nextReloc->r_type() != PPC_RELOC_PAIR ) {
-                                               printf("PPC_RELOC_SECTDIFF missing following pair\n");
-                                               break;
-                                       }
-                                       insertOffsetIfText(dontCleavePoints, sreloc->r_value());
-                                       insertOffsetIfText(dontCleavePoints, nextReloc->r_value());
-                               }
-                               break;
-                       case PPC_RELOC_PAIR:
-                               // do nothing, already used via a look ahead
-                               break;
-#endif
-#if defined(ARCH_I386)
-                       case GENERIC_RELOC_SECTDIFF:
-                       case GENERIC_RELOC_LOCAL_SECTDIFF:
-                               // these do not cleave up a .o file
-                               // a SECTDIFF in __TEXT probably means a jump table, and should prevent a cleave
-                               {
-                                       const macho_scattered_relocation_info* nextReloc = &sreloc[1];
-                                       if ( nextReloc->r_type() != GENERIC_RELOC_PAIR ) {
-                                               printf("GENERIC_RELOC_SECTDIFF missing following pair\n");
-                                               break;
-                                       }
-                                       insertOffsetIfText(dontCleavePoints, sreloc->r_value());
-                                       insertOffsetIfText(dontCleavePoints, nextReloc->r_value());
-                               }
-                               break;
-                       case GENERIC_RELOC_PAIR:
-                               // do nothing, already used via a look ahead
-                               break;
-#endif
-                       default:
-                               printf("unknown relocation type %d\n", sreloc->r_type());
-               }
-               
-       }
-}
-
-
-Segment* Reader::makeSegmentFromSection(const macho_section* sect)
-{
-       // make segment object if one does not already exist
-       const uint32_t segmentCount = fSegments.size();
-       for (uint32_t i=0; i < segmentCount; ++i) {
-               Segment* seg = fSegments[i];
-               if ( strcmp(sect->segname(), seg->getName()) == 0 )
-                       return seg;
-       }
-       Segment* seg = new Segment(sect);
-       fSegments.push_back(seg);
-       return seg;
-}
-
-macho_uintptr_t Reader::commonsOffset()
-{
-       return fSegment->vmsize();
-}
-
-const char*    Reader::getPath()
-{
-       return fPath;
-}
-
-std::vector<class ObjectFile::Atom*>&  Reader::getAtoms()
-{
-       return (std::vector<class ObjectFile::Atom*>&)(fAtoms);
-}
-
-std::vector<class ObjectFile::Atom*>*  Reader::getJustInTimeAtomsFor(const char* name)
-{
-       // object files have no just-in-time atoms
-       return NULL;
-}
-
-
-std::vector<ObjectFile::StabsInfo>*    Reader::getStabsDebugInfo()
-{
-       if ( fNonAtomStabsCount == 0 )
-               return NULL;
-               
-       std::vector<ObjectFile::StabsInfo>* stabs = new std::vector<ObjectFile::StabsInfo>();
-       stabs->reserve(fNonAtomStabsCount);
-       
-       for (uint32_t i=0; i < fNonAtomStabsCount; ++i) {
-               const macho_nlist* sym = &fSymbols[fNonAtomStabsStartIndex+i];
-               if ( (sym->n_type() & N_STAB) != 0 ) {
-                       ObjectFile::StabsInfo stab;
-                       stab.atomOffset = sym->n_value();
-                       stab.string             = &fStrings[sym->n_strx()];
-                       stab.type               = sym->n_type();
-                       stab.other              = sym->n_sect();
-                       stab.desc               = sym->n_desc();
-                       // for N_SO n_value is offset of first atom, but our gdb ignores this, so we omit that calculation
-                       if ( stab.type == N_SO ) 
-                               stab.atomOffset = 0;
-                       stabs->push_back(stab);
-               }
-       }
-       
-       // add any extra N_LSYM's not at start of symbol table
-       for (std::vector<uint32_t>::iterator it=fNonAtomExtras.begin(); it != fNonAtomExtras.end(); ++it) {
-               const macho_nlist* sym = &fSymbols[*it];
-               ObjectFile::StabsInfo stab;
-               stab.atomOffset = sym->n_value();
-               stab.string             = &fStrings[sym->n_strx()];
-               stab.type               = sym->n_type();
-               stab.other              = sym->n_sect();
-               stab.desc               = sym->n_desc();
-               stabs->push_back(stab);
-       }
-       
-       return stabs;
-}
-
-void Reader::deadStub(Atom& target)
-{
-       // remove stub
-       fDeadAtoms.insert(&target);
-               
-       // remove lazy pointer
-       const int stubNameLen = strlen(target.fSynthesizedName);
-       char lazyName[stubNameLen+8];
-       strcpy(lazyName, target.fSynthesizedName);
-       strcpy(&lazyName[stubNameLen-5], "$lazy_ptr");
-       const uint32_t atomCount = fAtoms.size();
-       for (uint32_t i=1; i < atomCount; ++i) {
-               Atom* atom = fAtoms[i];
-               if ( (atom->fSynthesizedName != NULL) && (strcmp(atom->fSynthesizedName, lazyName) == 0) ) {
-                       fDeadAtoms.insert(atom);
-                       break;
-               }
-       }
-}
-
-
-void Reader::addCallSiteReference(Atom& src, uint32_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint32_t picBaseOffset, uint32_t offsetInTargetAtom)
-{
-       // the compiler some times produces stub to static functions and then calls the stubs
-       // we need to skip the stub if a static function exists with the same name and remove the stub
-       if ( target.isLazyStub() ) {
-               const macho_section* section = target.fSection;
-               uint32_t index = (target.fOffset - section->addr()) / section->reserved2();
-               uint32_t indirectTableIndex = section->reserved1() + index;
-               uint32_t symbolIndex = ENDIAN_READ32(fIndirectTable[indirectTableIndex]);
-               if ( (symbolIndex & INDIRECT_SYMBOL_LOCAL) == 0 ) {
-                       const macho_nlist* sym = &fSymbols[symbolIndex];
-                       if ( (sym->n_value() != 0) && ((sym->n_type() & N_EXT) == 0) ) {
-                               Atom* betterTarget = this->findAtomCoveringOffset(sym->n_value());
-                               if ( (betterTarget != NULL) && (betterTarget->getScope() == ObjectFile::Atom::scopeTranslationUnit) ) {
-                                       // use direct reference to static function
-                                       src.addDirectReference(offsetInSrcAtom, kind, *betterTarget, offsetInTargetAtom, picBaseOffset);
-                                       
-                                       // remove stub and lazy pointer
-                                       this->deadStub(target);
-                                       return;
-                               }
-                       }
-               }
-       }
-       
-       // fall through to general case
-       src.addReference(offsetInSrcAtom, kind, target, offsetInTargetAtom, picBaseOffset);
-}
-
-
-Atom::Atom(Reader& owner, const macho_nlist* symbol)
- : fOwner(owner), fSymbol(symbol), fOffset(0), fSize(0), fSection(NULL), fSegment(NULL), fSynthesizedName(NULL),
-       fStabsStartIndex(0), fStabsCount(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
-               const macho_section* sections = (macho_section*)((char*)fOwner.fSegment + sizeof(macho_segment_command));
-               fSection = &sections[fSymbol->n_sect()-1];
-               fSegment = owner.makeSegmentFromSection(fSection);
-               fOffset = fSymbol->n_value();
-               uint8_t type = fSection->flags() & SECTION_TYPE;
-               switch ( type ) {
-                       case S_LAZY_SYMBOL_POINTERS:
-                       case S_NON_LAZY_SYMBOL_POINTERS:
-                               {
-                                       // get target name out of indirect symbol table
-                                       uint32_t index = (fOffset - fSection->addr()) / sizeof(macho_uintptr_t);
-                                       index += fSection->reserved1();
-                                       uint32_t symbolIndex = ENDIAN_READ32(fOwner.fIndirectTable[index]);
-                                       uint32_t strOffset = fOwner.fSymbols[symbolIndex].n_strx();
-                                       const char* name = &fOwner.fStrings[strOffset];
-                                       Reference* ref = this->addByNameReference(0, Reference::pointer, name, 0, 0);
-                                       if ( type == S_LAZY_SYMBOL_POINTERS ) {
-                                               ref->setLazy(true);
-                                       }
-                               }
-                               break;
-               }
-       }
-       else if ( ((type & N_TYPE) == N_UNDF) && (symbol->n_value() != 0) ) {
-               // tentative definition
-               fSize = symbol->n_value();
-               fSection = getCommonsSection();
-               fSegment = owner.makeSegmentFromSection(fSection);
-               fOffset = owner.commonsOffset();
-       }
-       else {
-               printf("unknown symbol type: %d\n", type);
-       }       
-}
-
-Atom::Atom(Reader& owner, uint32_t offset)
- : fOwner(owner), fSymbol(NULL), fOffset(offset), fSize(0), fSection(NULL), fSegment(NULL), fSynthesizedName(NULL),
-       fStabsStartIndex(0), fStabsCount(0)
-{
-       fSection = findSectionFromOffset(offset);
-       fScope = ObjectFile::Atom::scopeLinkageUnit;
-       fSegment = owner.makeSegmentFromSection(fSection);
-       uint8_t type = fSection->flags() & SECTION_TYPE;
-       switch ( type ) {
-               case S_SYMBOL_STUBS:
-                       {
-                               uint32_t index = (offset - fSection->addr()) / fSection->reserved2(); 
-                               index += fSection->reserved1();
-                               uint32_t symbolIndex = ENDIAN_READ32(fOwner.fIndirectTable[index]);
-                               uint32_t strOffset = fOwner.fSymbols[symbolIndex].n_strx();
-                               const char* name = &fOwner.fStrings[strOffset];
-                               char* str = new char[strlen(name)+8];
-                               strcpy(str, name);
-                               strcat(str, "$stub");
-                               fSynthesizedName = str;
-                       }
-                       break;
-               case S_LAZY_SYMBOL_POINTERS:
-               case S_NON_LAZY_SYMBOL_POINTERS:
-                       {
-                               uint32_t index = (offset - fSection->addr()) / sizeof(macho_uintptr_t);
-                               index += fSection->reserved1();
-                               uint32_t symbolIndex = ENDIAN_READ32(fOwner.fIndirectTable[index]);
-                               uint32_t strOffset = fOwner.fSymbols[symbolIndex].n_strx();
-                               const char* name = &fOwner.fStrings[strOffset];
-                               char* str = new char[strlen(name)+16];
-                               strcpy(str, name);
-                               if ( type == S_LAZY_SYMBOL_POINTERS )
-                                       strcat(str, "$lazy_ptr");
-                               else
-                                       strcat(str, "$non_lazy_ptr");
-                               fSynthesizedName = str;
-                               Reference* ref = this->addByNameReference(0, Reference::pointer, name, 0, 0);
-                               if ( type == S_LAZY_SYMBOL_POINTERS ) {
-                                       ref->setLazy(true);
-                               }
-                               const macho_nlist* sym = &fOwner.fSymbols[symbolIndex];
-                               if ( (sym->n_type() & N_TYPE) == N_UNDF ) {
-                                       if ( (sym->n_desc() & N_WEAK_REF) != 0 )
-                                               ref->setWeak(true);
-                               }
-                       }
-                       break;
-       }
-}
-
-
-Atom::~Atom()
-{
-}
-
-macho_section Atom::fgCommonsSection;
-
-
-bool Atom::isLazyStub()
-{
-       return ( (fSection->flags() & SECTION_TYPE) == S_SYMBOL_STUBS);
-}
-
-const macho_section* Atom::getCommonsSection() {
-       if ( strcmp(fgCommonsSection.sectname(), "__common") != 0 ) {
-               fgCommonsSection.set_sectname("__common");
-               fgCommonsSection.set_segname("__DATA");
-               fgCommonsSection.set_flags(S_ZEROFILL);
-       }
-       return &fgCommonsSection;
-}
-
-ObjectFile::Reader* Atom::getFile() const
-{
-       return &fOwner;
-}
-
-
-const char* Atom::getName() const
-{
-       if ( fSymbol != NULL )
-               return &fOwner.fStrings[fSymbol->n_strx()];
-       else
-               return fSynthesizedName;
-}
-
-const char* Atom::getDisplayName() const
-{
-       if ( fSymbol != NULL )
-               return &fOwner.fStrings[fSymbol->n_strx()];
-       
-       if ( fSynthesizedName != NULL )
-               return fSynthesizedName;
-               
-       static char temp[32];
-       sprintf(temp, "atom #%u", fOwner.findAtomIndex(*this));
-       return temp;
-}
-
-ObjectFile::Atom::Scope Atom::getScope() const
-{
-       return fScope;
-}
-
-void Atom::setScope(ObjectFile::Atom::Scope newScope)
-{
-       fScope = newScope;
-}
-
-
-bool Atom::isWeakDefinition() const
-{
-       if ( isTentativeDefinition() )
-               return true;
-       if ( fSymbol != NULL ) 
-               return ( (fSymbol->n_desc() & N_WEAK_DEF) != 0 );
-       uint8_t type = fSection->flags() & SECTION_TYPE;
-       switch ( type ) {
-               case S_SYMBOL_STUBS:
-               case S_LAZY_SYMBOL_POINTERS:
-               case S_NON_LAZY_SYMBOL_POINTERS:
-                       return true;
-       }
-       return false;
-}
-
-bool Atom::isTentativeDefinition() const
-{
-       return (fSection == &fgCommonsSection);
-}
-
-bool Atom::isCoalesableByName() const
-{
-       uint8_t type = fSection->flags() & SECTION_TYPE;
-       switch ( type ) {
-               case S_SYMBOL_STUBS:
-               case S_COALESCED:
-                       return true;
-       };
-       if ( isTentativeDefinition() )
-               return true;
-       return false;
-}
-
-bool Atom::isCoalesableByValue() const
-{
-       uint8_t type = fSection->flags() & SECTION_TYPE;
-       switch ( type ) {
-               case S_CSTRING_LITERALS:
-               case S_4BYTE_LITERALS:
-               case S_8BYTE_LITERALS:
-                       return true;
-       };
-       return false;
-}
-
-bool Atom::isZeroFill() const
-{
-       return ((fSection->flags() & SECTION_TYPE) == S_ZEROFILL);
-}
-
-bool Atom::dontDeadStrip() const
-{
-       if ( fSymbol != NULL ) 
-               return ( (fSymbol->n_desc() & N_NO_DEAD_STRIP) != 0 );
-       return false;
-}
-
-
-bool Atom::dontStripName() const
-{
-       if ( fSymbol != NULL ) 
-               return ( (fSymbol->n_desc() & REFERENCED_DYNAMICALLY) != 0 );
-       return false;
-}
-
-bool Atom::isImportProxy() const
-{
-       return false;
-}
-       
-
-uint64_t Atom::getSize() const
-{
-       //return fOffset;
-       return fSize;
-}
-
-
-std::vector<ObjectFile::Reference*>& Atom::getReferences() const
-{
-       return (std::vector<ObjectFile::Reference*>&)(fReferences);
-}
-
-bool Atom::mustRemainInSection() const
-{
-       return true;
-}
-
-const char*     Atom::getSectionName() const
-{
-       if ( strlen(fSection->sectname()) > 15 ) {
-               static char temp[18];
-               strncpy(temp, fSection->sectname(), 16);
-               temp[17] = '\0';
-               return temp;
-       }
-       return fSection->sectname();
-}
-
-Segment& Atom::getSegment() const
-{
-       return *fSegment;
-}
-
-bool Atom::requiresFollowOnAtom() const
-{
-       // requires follow-on if built with old compiler and not the last atom
-       if ( (fOwner.fHeader->flags() & MH_SUBSECTIONS_VIA_SYMBOLS) == 0) {
-               if ( fOwner.findAtomIndex(*this) < (fOwner.fAtoms.size()-1) )
-                       return true;
-       }
-       return false;
-}
-
-ObjectFile::Atom& Atom::getFollowOnAtom() const
-{
-       uint32_t myIndex = fOwner.findAtomIndex(*this);
-       return *fOwner.fAtoms[myIndex+1];
-}
-
-std::vector<ObjectFile::StabsInfo>* Atom::getStabsDebugInfo() const
-{
-       if ( fStabsCount == 0 )
-               return NULL;
-               
-       std::vector<ObjectFile::StabsInfo>* stabs = new std::vector<ObjectFile::StabsInfo>();
-       stabs->reserve(fStabsCount);
-       
-       for (uint32_t i=0; i < fStabsCount; ++i) {
-               const macho_nlist* sym = &fOwner.fSymbols[fStabsStartIndex+i];
-               if ( (sym->n_type() & N_STAB) != 0 ) {
-                       ObjectFile::StabsInfo stab;
-                       stab.atomOffset = sym->n_value();
-                       stab.string             = &fOwner.fStrings[sym->n_strx()];
-                       stab.type               = sym->n_type();
-                       stab.other              = sym->n_sect();
-                       stab.desc               = sym->n_desc();
-                       switch ( stab.type ) {
-                               case N_FUN:
-                                       if ( stab.other == 0 )
-                                               break;
-                                       // end of function N_FUN has size (not address) so should not be adjusted
-                                       // fall through
-                               case N_BNSYM:
-                               case N_ENSYM:
-                               case N_LBRAC:
-                               case N_RBRAC:
-                               case N_SLINE:
-                               case N_STSYM:
-                               case N_LCSYM:
-                                       // all these stab types need their value changed from an absolute address to the atom offset
-                                       stab.atomOffset -= fOffset;
-                                       break;
-                       }
-                       stabs->push_back(stab);
-               }
-       }
-       
-       return stabs;
-}
-
-uint8_t        Atom::getAlignment() const
-{
-       // mach-o file format has no alignment information for atoms - just whole sections
-       if ( fSection != NULL ) {
-               if ( isTentativeDefinition() ) {
-                       // common symbols align to their size
-                       // that is, a 4-byte common aligns to 4-bytes
-                       // to be safe, odd size commons align to the next power-of-2 size
-                       uint8_t alignment = (uint8_t)ceil(log2(this->getSize()));
-                       // limit alignment of extremely large commons to 2^15 bytes (8-page)
-                       if ( alignment < 15 )
-                               return alignment;
-                       else
-                               return 15;
-               }
-               else {
-                       // so we assume every atom requires the same alignment as the whole section
-                       return fSection->align();
-               }
-       }
-       else {
-               return 2;
-       }
-}
-
-void Atom::copyRawContent(uint8_t buffer[]) const
-{
-       // copy base bytes
-       if ( isZeroFill() )
-               bzero(buffer, fSize);
-       else {
-               uint32_t fileOffset = fSection->offset() - fSection->addr() + fOffset;
-               memcpy(buffer, (char*)(fOwner.fHeader)+fileOffset, fSize);
-       }
-}
-
-void Atom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
-       const uint32_t referencesCount = fReferences.size();
-
-       // skip copy if no fix-ups
-       if ( referencesCount == 0 ) {
-               uint32_t fileOffset = fSection->offset() - fSection->addr() + fOffset;
-               writer.write(0, (char*)(fOwner.fHeader)+fileOffset, fSize);
-               return;
-       }
-       
-       // copy base bytes
-       uint8_t buffer[this->getSize()];
-       this->copyRawContent(buffer);
-
-       // apply any fix-ups
-       for (uint32_t i=0; i < referencesCount; ++i) {
-               Reference* ref = fReferences[i];
-               uint32_t offset = ref->getFixUpOffset();
-               uint32_t* instructionPtr = (uint32_t*)&buffer[offset];
-               ObjectFile::Atom& target = ref->getTarget();
-               if ( &target == NULL ) {
-                       if ( finalLinkedImage )
-                               throw "target not found";
-                       else
-                               continue;
-               }
-               uint32_t instruction;
-               uint32_t newInstruction;
-               switch ( ref->getKind() ) {
-                       case Reference::noFixUp:
-                               break;
-                       case Reference::pointer:
-                               {
-                                       //fprintf(stderr, "writeContent: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
-                                       if ( ref->isLazyReference() && finalLinkedImage ) {
-                                               // lazy-symbol ==> pointer contains address of dyld_stub_binding_helper (stored in "from" target)
-                                               *((macho_uintptr_t*)instructionPtr) = ENDIAN_SWAP_POINTER(ref->getFromTarget().getAddress());
-                                       }
-                                       else if ( target.isImportProxy() ) {
-                                               // external realocation ==> pointer contains addend
-                                               *((macho_uintptr_t*)instructionPtr) = ENDIAN_SWAP_POINTER(ref->getTargetOffset());
-                                       }
-                                       else {
-                                               // internal relocation
-                                               if ( finalLinkedImage || (strcmp(target.getSectionName(), "__common") != 0) ) {
-                                                       // pointer contains target address
-                                                       //printf("Atom::writeContent() target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
-                                                       *((macho_uintptr_t*)instructionPtr) = ENDIAN_SWAP_POINTER(target.getAddress() + ref->getTargetOffset());
-                                               }
-                                               else {
-                                                       // pointer contains addend
-                                                       *((macho_uintptr_t*)instructionPtr) = ENDIAN_SWAP_POINTER(ref->getTargetOffset());
-                                               }
-                                       }
-                               }
-                               break;
-                       case Reference::ppcFixupBranch24:
-                               {
-                                       //fprintf(stderr, "bl fixup to %s at 0x%08llX, ", target.getDisplayName(), target.getAddress());
-                                       int64_t displacement = (target.getAddress() + ref->getTargetOffset() ) - (this->getAddress() + offset);
-                                       if ( !finalLinkedImage && target.isImportProxy() )  {
-                                               // 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 -= target.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 in %s to %s in %s", displacement, this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath());
-                                               }
-                                       }
-                                       instruction = OSReadBigInt32(instructionPtr, 0);
-                                       newInstruction = (instruction & 0xFC000003) | ((uint32_t)displacement & 0x03FFFFFC);
-                                       //fprintf(stderr, "bl fixup: 0x%08X -> 0x%08X\n", instruction, newInstruction);
-                                       OSWriteBigInt32(instructionPtr, 0, newInstruction);                     
-                               }
-                               break;
-                       case Reference::ppcFixupBranch14:
-                               break;
-                       case Reference::ppcFixupPicBaseLow16:
-                               {
-                                       uint64_t targetAddr = target.getAddress() + ref->getTargetOffset();
-                                       uint64_t picBaseAddr = this->getAddress() + ref->getFromTargetOffset();
-                                       int64_t displacement = targetAddr - picBaseAddr;
-                                       const int64_t picbase_twoGigLimit = 0x80000000;
-                                       if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
-                                               throw "32-bit pic-base out of range";
-                                       uint16_t instructionLowHalf = (displacement & 0xFFFF);
-                                       instruction = OSReadBigInt32(instructionPtr, 0);
-                                       newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
-                                       OSWriteBigInt32(instructionPtr, 0, newInstruction);                     
-                               }
-                               break;
-                       case Reference::ppcFixupPicBaseLow14:
-                               {
-                                       uint64_t targetAddr = target.getAddress() + ref->getTargetOffset();
-                                       uint64_t picBaseAddr = this->getAddress() + ref->getFromTargetOffset();
-                                       int64_t displacement = targetAddr - picBaseAddr;
-                                       const int64_t picbase_twoGigLimit = 0x80000000;
-                                       if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) )
-                                               throw "32-bit pic-base out of range";
-                                       uint16_t instructionLowHalf = (displacement & 0xFFFF);
-                                       if ( (instructionLowHalf & 0x3) != 0 )
-                                               throw "bad address for lo14 instruction fix-up";
-                                       instruction = OSReadBigInt32(instructionPtr, 0);
-                                       newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf;
-                                       OSWriteBigInt32(instructionPtr, 0, newInstruction);                     
-                               }
-                               break;
-                       case Reference::ppcFixupPicBaseHigh16:
-                               {
-                                       uint64_t targetAddr = target.getAddress() + ref->getTargetOffset();
-                                       uint64_t picBaseAddr = this->getAddress() + ref->getFromTargetOffset();
-                                       int64_t displacement = targetAddr - picBaseAddr;
-                                       const int64_t picbase_twoGigLimit = 0x80000000;
-                                       if ( (displacement > picbase_twoGigLimit) || (displacement < (-picbase_twoGigLimit)) ) 
-                                               throw "32-bit pic-base out of range";
-                                       uint16_t instructionLowHalf = displacement >> 16;
-                                       if ( (displacement & 0x00008000) != 0 ) 
-                                               ++instructionLowHalf;
-                                       instruction = OSReadBigInt32(instructionPtr, 0);
-                                       newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
-                                       OSWriteBigInt32(instructionPtr, 0, newInstruction);                     
-                               }
-                               break;
-                       case Reference::ppcFixupAbsLow16:
-                               {
-                                       int64_t addr = target.getAddress() + ref->getTargetOffset();
-                                       if ( !finalLinkedImage && target.isImportProxy() )
-                                               addr -= target.getAddress() ;
-                                       uint16_t instructionLowHalf = (addr & 0xFFFF);
-                                       instruction = OSReadBigInt32(instructionPtr, 0);
-                                       newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
-                                       OSWriteBigInt32(instructionPtr, 0, newInstruction);                     
-                               }
-                               break;
-                       case Reference::ppcFixupAbsLow14:
-                               {
-                                       int64_t addr = target.getAddress() + ref->getTargetOffset();
-                                       if ( !finalLinkedImage && target.isImportProxy() )
-                                               addr -= target.getAddress() ;
-                                       uint16_t instructionLowHalf = (addr & 0xFFFF);
-                                       if ( (instructionLowHalf & 0x3) != 0 )
-                                               throw "bad address for lo14 instruction fix-up";
-                                       instruction = OSReadBigInt32(instructionPtr, 0);
-                                       newInstruction = (instruction & 0xFFFF0003) | instructionLowHalf;
-                                       OSWriteBigInt32(instructionPtr, 0, newInstruction);                     
-                               }
-                               break;
-                       case Reference::ppcFixupAbsHigh16:
-                               {
-                                       int64_t addr = target.getAddress() + ref->getTargetOffset();
-                                       if ( !finalLinkedImage && target.isImportProxy() )
-                                               addr -= target.getAddress() ;
-                                       uint16_t hi16 = (addr >> 16);
-                                       instruction = OSReadBigInt32(instructionPtr, 0);
-                                       newInstruction = (instruction & 0xFFFF0000) | hi16;
-                                       OSWriteBigInt32(instructionPtr, 0, newInstruction);     
-                               }
-                               break;
-                       case Reference::ppcFixupAbsHigh16AddLow:
-                               {
-                                       int64_t addr = target.getAddress() + ref->getTargetOffset();
-                                       if ( !finalLinkedImage && target.isImportProxy() )
-                                               addr -= target.getAddress() ;
-                                       if ( addr & 0x00008000 )
-                                               addr += 0x00010000;
-                                       instruction = OSReadBigInt32(instructionPtr, 0);
-                                       newInstruction = (instruction & 0xFFFF0000) | (addr >> 16);
-                                       OSWriteBigInt32(instructionPtr, 0, newInstruction);     
-                               }
-                               break;
-                       case Reference::pointer32Difference:
-                               ENDIAN_WRITE32(*instructionPtr, target.getAddress() + ref->getTargetOffset() - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()));
-                               break;
-                       case Reference::pointer64Difference:
-                               *((uint64_t*)instructionPtr) = ENDIAN_SWAP64(target.getAddress() + ref->getTargetOffset() - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()));
-                               break;
-                       case Reference::x86FixupBranch32:
-                               {
-                                       int64_t displacement = target.getAddress() - (this->getAddress() + offset);
-                                       if ( target.isImportProxy() )  {
-                                               displacement = 0;
-                                       }
-                                       else {
-                                               const int64_t bl_twoGigLimit = 0x7FFFFFFF;
-                                               if ( (displacement > bl_twoGigLimit) || (displacement < (-bl_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 "call out of range";
-                                               }
-                                       }
-                                       OSWriteLittleInt32(instructionPtr, 0, (int32_t)displacement);                   
-                               }
-                               break;
-               }
-       }
-
-       // write out
-       writer.write(0, buffer, getSize());
-}
-
-
-
-const macho_section* Atom::findSectionFromOffset(uint32_t offset)
-{
-       const macho_section* const sectionsStart = (const macho_section*)( (char*)fOwner.fSegment + sizeof(macho_segment_command) );
-       const macho_section* const sectionsEnd   = &sectionsStart[fOwner.fSegment->nsects()];
-       for (const macho_section* s = sectionsStart; s < sectionsEnd; ++s) {
-               if ( (s->addr() <= offset) && (offset < (s->addr()+s->size())) ) 
-                       return s;
-       }
-       throwf("address 0x%08X is not in any section", offset);
-}
-
-void Atom::setSize(macho_uintptr_t size)
-{
-       fSize = size;
-}
-
-
-void Atom::setFollowOnAtom(Atom&)
-{
-
-}
-
-Reference* Atom::addReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint64_t offsetInTarget, uint64_t offsetInFromTarget)
-{
-       if ( (target.getScope() != ObjectFile::Atom::scopeTranslationUnit) && ((target.fSymbol != NULL) || (target.fSynthesizedName != NULL)) )
-               return this->addByNameReference(offsetInSrcAtom, kind, target.getName(), offsetInTarget, offsetInFromTarget);
-       else 
-               return this->addDirectReference(offsetInSrcAtom, kind, target, offsetInTarget, offsetInFromTarget);
-}
-
-
-Reference* Atom::addDirectReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint64_t offsetInTarget, uint64_t offsetInFromTarget)
-{      
-       Reference* ref = new Reference(offsetInSrcAtom, kind, target, offsetInTarget, offsetInFromTarget);
-       // in rare cases, there may already be a by-name reference to the same atom.  If so, replace with this direct reference
-       for (std::vector<Reference*>::iterator it=fReferences.begin(); it != fReferences.end(); it++) {
-               ObjectFile::Reference* aRef = *it;
-               if ( (aRef->getFixUpOffset() == offsetInSrcAtom) && (aRef->getKind() == kind) ) {
-                       *it = ref;
-                       return ref;
-               }
-       }
-       
-       // note: adding to start of list because mach-o relocs are in reverse offset order in the .o file
-       fReferences.insert(fReferences.begin(), ref);
-       return ref;
-}
-
-Reference* Atom::addByNameReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, const char* targetName, uint64_t offsetInTarget, uint64_t offsetInFromTarget)
-{
-       Reference* ref = new Reference(offsetInSrcAtom, kind, targetName, offsetInTarget, offsetInFromTarget);
-       // note: adding to start of list because mach-o relocs are in reverse offset order in the .o file
-       fReferences.insert(fReferences.begin(), ref);
-       return ref;
-}
-
-Reference* Atom::addDifferenceReference(macho_uintptr_t offsetInSrcAtom, Reference::Kind kind, Atom& target, uint64_t offsetInTarget, Atom& fromTarget, uint64_t offsetInFromTarget)
-{
-       Reference* ref = new Reference(offsetInSrcAtom, kind, target, offsetInTarget, fromTarget, offsetInFromTarget);
-       // note: adding to start of list because mach-o relocs are in reverse offset order in the .o file
-       fReferences.insert(fReferences.begin(), ref);
-       return ref;
-}
-
-
-Segment::Segment(const macho_section* sect)
-       : fSection(sect)
-{
-}
-
-const char* Segment::getName() const
-{
-       return fSection->segname();
-}
-
-bool Segment::isContentReadable() const
-{
-       return true;
-}
-
-bool Segment::isContentWritable() const
-{
-       if ( strcmp(fSection->segname(), "__DATA") == 0 )
-               return true;
-       if ( strcmp(fSection->segname(), "__OBJC") == 0 )
-               return true;
-       return false;
-}
-
-bool Segment::isContentExecutable() const
-{
-       return ( strcmp(fSection->segname(), "__TEXT") == 0 );
-}
-
-       
-Reference::Reference(macho_uintptr_t fixUpOffset, Kind kind, const char* targetName, uint64_t offsetInTarget, uint64_t offsetInFromTarget)
- : fTarget(NULL), fFromTarget(NULL), fTargetName(targetName), fFromTargetName(NULL), fTargetOffset(offsetInTarget), fFromTargetOffset(offsetInFromTarget),
-  fFixUpOffsetInSrc(fixUpOffset), fKind(kind), fLazy(false), fWeak(false)
-{
-}
-
-Reference::Reference(macho_uintptr_t fixUpOffset, Kind kind, class Atom& target, uint64_t offsetInTarget, uint64_t offsetInFromTarget)
- : fTarget(&target), fFromTarget(NULL), fTargetName(NULL), fFromTargetName(NULL), fTargetOffset(offsetInTarget), fFromTargetOffset(offsetInFromTarget), 
- fFixUpOffsetInSrc(fixUpOffset), fKind(kind), fLazy(false), fWeak(false)
-{
-}
-
-Reference::Reference(macho_uintptr_t fixUpOffset, Kind kind, class Atom& target, uint64_t offsetInTarget, class Atom& fromTarget, uint64_t offsetInFromTarget)
- : fTarget(&target), fFromTarget(&fromTarget), fTargetName(NULL), fFromTargetName(NULL), fTargetOffset(offsetInTarget), fFromTargetOffset(offsetInFromTarget),
-  fFixUpOffsetInSrc(fixUpOffset), fKind(kind), fLazy(false), fWeak(false)
-{
-       // assure no direct references to something that might be coalesced
-       if ( (target.isWeakDefinition() || target.isCoalesableByName()) && (target.getScope() != ObjectFile::Atom::scopeTranslationUnit) && (target.getName() != NULL) ) {
-               //fprintf(stderr, "change TO direct reference to by-name: from %s to %s in %p\n", fromTarget.getDisplayName(), target.getName(), this);
-               fTargetName = target.getName();
-               fTarget = NULL;
-       }
-// Note: We should also allow by-name from references, but many other chunks of code assume from targets are always direct//
-//     if ( (fromTarget.isWeakDefinition() || fromTarget.isCoalesableByName()) && (fromTarget.getScope() != ObjectFile::Atom::scopeTranslationUnit) && (fromTarget.getName() != NULL)) {
-//             fprintf(stderr, "change FROM direct reference to by-name: from %s to %s in %p\n", fromTarget.getDisplayName(), target.getName(), this);
-//             fFromTargetName = fromTarget.getName();
-//             fFromTarget = NULL;
-//     }
-}
-
-
-
-Reference::~Reference()
-{
-}
-
-bool Reference::isTargetUnbound() const
-{
-       return ( fTarget == NULL );
-}
-
-bool Reference::isFromTargetUnbound() const
-{
-       return ( fFromTarget == NULL );
-}
-
-bool Reference::isWeakReference() const
-{
-       return fWeak;
-}
-
-bool Reference::requiresRuntimeFixUp(bool slideable) const
-{
-       // This static linker only supports pure code (no code fixups are runtime)
-#if defined(ARCH_PPC) || defined(ARCH_PPC64)
-       // Only data can be fixed up, and the codegen assures only "pointers" need runtime fixups
-       return ( (fKind == Reference::pointer) && (fTarget->isImportProxy() || fTarget->isWeakDefinition() || slideable) );
-#elif defined(ARCH_I386)
-       // For i386, Reference::pointer is used for both data pointers and instructions with 32-bit absolute operands
-       if ( fKind == Reference::pointer ) {
-               if ( fTarget->isImportProxy() )
-                       return true;
-               else
-                       return slideable;
-       }
-       return false; 
-#else
-       #error
-#endif
-}
-
-bool Reference::isLazyReference() const
-{
-       return fLazy;
-}
-
-ObjectFile::Reference::Kind    Reference::getKind() const
-{
-       return fKind;
-}
-
-uint64_t Reference::getFixUpOffset() const
-{
-       return fFixUpOffsetInSrc;
-}
-
-const char* Reference::getTargetName() const
-{
-       if ( fTargetName != NULL )
-               return fTargetName;
-       return fTarget->getName();
-}
-
-ObjectFile::Atom& Reference::getTarget() const
-{
-       return *fTarget;
-}
-
-void Reference::setTarget(ObjectFile::Atom& target, uint64_t offset)
-{
-       fTarget = &target;
-       fTargetOffset = offset;
-}
-
-
-ObjectFile::Atom& Reference::getFromTarget() const
-{
-       return *fFromTarget;
-}
-
-bool Reference::hasFromTarget() const
-{
-       return ( (fFromTarget != NULL) || (fFromTargetName != NULL) );
-}
-
-const char* Reference::getFromTargetName() const
-{
-       if ( fFromTargetName != NULL )
-               return fFromTargetName;
-       return fFromTarget->getName();
-}
-
-void Reference::setFromTarget(ObjectFile::Atom& target)
-{
-       fFromTarget = &target;
-}
-
-void Reference::setFromTargetName(const char* name)
-{
-       fFromTargetName = name;
-}
-
-void Reference::setFromTargetOffset(uint64_t offset)
-{
-       fFromTargetOffset = offset;
-}
-
-uint64_t Reference::getTargetOffset() const
-{
-       return fTargetOffset;
-}
-
-
-uint64_t Reference::getFromTargetOffset() const
-{
-       return fFromTargetOffset;
-}
-
-void Reference::setLazy(bool lazy)
-{
-       fLazy = lazy;
-}
-
-void Reference::setWeak(bool weak)
-{
-       fWeak = weak;
-}
-
-const char* Reference::getDescription() const
-{
-       static char temp[256];
-       if ( fKind == pointer32Difference ) {
-               // by-name references have quoted names
-               bool targetByName = ( &(this->getTarget()) == NULL );
-               bool fromByName   = ( &(this->getFromTarget()) == NULL );
-               const char* targetQuotes = targetByName ? "\"" : "";
-               const char* fromQuotes = fromByName ? "\"" : "";
-               sprintf(temp, "offset 0x%04llX, 32-bit pointer difference: (&%s%s%s + %lld) - (&%s%s%s + %lld)", 
-                       this->getFixUpOffset(), targetQuotes, this->getTargetName(), targetQuotes, this->getTargetOffset(), 
-                                                  fromQuotes, this->getFromTargetName(), fromQuotes, this->getFromTargetOffset() );
-       }
-       else if ( fKind == pointer64Difference ) {
-               // by-name references have quoted names
-               bool targetByName = ( &(this->getTarget()) == NULL );
-               bool fromByName   = ( &(this->getFromTarget()) == NULL );
-               const char* targetQuotes = targetByName ? "\"" : "";
-               const char* fromQuotes = fromByName ? "\"" : "";
-               sprintf(temp, "offset 0x%04llX, 64-bit pointer difference: (&%s%s%s + %lld) - (&%s%s%s + %lld)", 
-                       this->getFixUpOffset(), targetQuotes, this->getTargetName(), targetQuotes, this->getTargetOffset(), 
-                                                  fromQuotes, this->getFromTargetName(), fromQuotes, this->getFromTargetOffset() );
-       }
-       else {
-               switch( fKind ) {
-                       case noFixUp:
-                               sprintf(temp, "reference to ");
-                               break;
-                       case pointer:
-                               {
-                               const char* weak = "";
-                               if ( fWeak )
-                                       weak = "weak ";
-                               const char* lazy = "";
-                               if ( fLazy )
-                                       lazy = "lazy ";
-                               sprintf(temp, "offset 0x%04llX, %s%spointer to ", this->getFixUpOffset(), weak, lazy);
-                               }
-                               break;
-                       case ppcFixupBranch14:
-                       case ppcFixupBranch24:
-                               sprintf(temp, "offset 0x%04llX, bl pc-rel fixup to ", this->getFixUpOffset());
-                               break;
-                       case ppcFixupPicBaseLow16:
-                               sprintf(temp, "offset 0x%04llX, low  16 fixup from pic-base offset 0x%04llX to ", this->getFixUpOffset(), this->getFromTargetOffset());
-                               break;
-                       case ppcFixupPicBaseLow14:
-                               sprintf(temp, "offset 0x%04llX, low  14 fixup from pic-base offset 0x%04llX to ", this->getFixUpOffset(), this->getFromTargetOffset());
-                               break;
-                       case ppcFixupPicBaseHigh16:
-                               sprintf(temp, "offset 0x%04llX, high 16 fixup from pic-base offset 0x%04llX to ", this->getFixUpOffset(), this->getFromTargetOffset());
-                               break;
-                       case ppcFixupAbsLow16:
-                               sprintf(temp, "offset 0x%04llX, low  16 fixup to absolute address of ", this->getFixUpOffset());
-                               break;
-                       case ppcFixupAbsLow14:
-                               sprintf(temp, "offset 0x%04llX, low  14 fixup to absolute address of ", this->getFixUpOffset());
-                               break;
-                       case ppcFixupAbsHigh16:
-                               sprintf(temp, "offset 0x%04llX, high 16 fixup to absolute address of ", this->getFixUpOffset());
-                               break;
-                       case ppcFixupAbsHigh16AddLow:
-                               sprintf(temp, "offset 0x%04llX, high 16 fixup to absolute address of ", this->getFixUpOffset());
-                               break;
-                       case pointer32Difference:
-                       case pointer64Difference:
-                               // handled above
-                               break;
-                       case x86FixupBranch32:
-                               sprintf(temp, "offset 0x%04llX, pc-rel fixup to ", this->getFixUpOffset());
-                               break;
-               }
-               // always quote by-name references
-               if ( fTargetName != NULL ) {
-                       strcat(temp, "\"");
-                       strcat(temp, fTargetName);
-                       strcat(temp, "\"");
-               }
-               else if ( fTarget != NULL ) {
-                       strcat(temp, fTarget->getDisplayName());
-               }
-               else {
-                       strcat(temp, "NULL target");
-               }
-               if ( fTargetOffset != 0 )
-                       sprintf(&temp[strlen(temp)], " plus 0x%08llX", this->getTargetOffset());
-               if ( (fKind==pointer) && fLazy ) {
-                       strcat(temp, " initially bound to \"");
-                       if ( (fFromTarget != NULL) || (fFromTargetName != NULL) ) {
-                               strcat(temp, this->getFromTargetName());
-                               strcat(temp, "\"");
-                               if ( this->getFromTargetOffset() != 0 ) 
-                                       sprintf(&temp[strlen(temp)], " plus 0x%08llX", this->getFromTargetOffset());
-                       }
-                       else {
-                               strcat(temp, "\" << missing >>");
-                       }
-               }
-       }
-       return temp;
-}
-
-};
-
-
-
-
-
-
-
index 4d48a3714529c9641826cbc30b1248a4da519a62..7296c1a96e16df0d9a0361d9a0cc5cbeaa715ac6 100644 (file)
@@ -1,5 +1,6 @@
-/*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2005-2006 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -48,9 +49,11 @@ public:
        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()                                                              { return fAtoms; }
        virtual std::vector<class ObjectFile::Atom*>*   getJustInTimeAtomsFor(const char* name) { return NULL; }
-       virtual std::vector<ObjectFile::StabsInfo>*             getStabsDebugInfo()                                             { return NULL; }
+       virtual std::vector<Stab>*                                              getStabs()                                                              { return NULL; }
 
 private:
        const char*                                                                             fPath;
@@ -61,17 +64,13 @@ private:
 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 NULL; }
        virtual const char*                                                     getDisplayName() const;
        virtual Scope                                                           getScope() const                        { return ObjectFile::Atom::scopeTranslationUnit; }
-       virtual bool                                                            isTentativeDefinition() const { return false; }
-       virtual bool                                                            isWeakDefinition() const        { return false; }
-       virtual bool                                                            isCoalesableByName() const      { return false; }
-       virtual bool                                                            isCoalesableByValue() const { return false; }
+       virtual DefinitionKind                                          getDefinitionKind() const       { return kRegularDefinition; }
+       virtual SymbolTableInclusion                            getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
        virtual bool                                                            isZeroFill() const                      { return false; }
-       virtual bool                                                            dontDeadStrip() const           { return true; }
-       virtual bool                                                            dontStripName() const           { return false; }
-       virtual bool                                                            isImportProxy() const           { return false; }
        virtual uint64_t                                                        getSize() const                         { return fFileLength; }
        virtual std::vector<ObjectFile::Reference*>&  getReferences() const             { return fgEmptyReferenceList; }
        virtual bool                                                            mustRemainInSection() const { return false; }
@@ -79,20 +78,17 @@ public:
        virtual Segment&                                                        getSegment() const                      { return fSegment; }
        virtual bool                                                            requiresFollowOnAtom() const{ return false; }
        virtual ObjectFile::Atom&                                       getFollowOnAtom() const         { return *((ObjectFile::Atom*)NULL); }
-       virtual std::vector<ObjectFile::StabsInfo>*     getStabsDebugInfo() const       { return NULL; }
+       virtual std::vector<ObjectFile::LineInfo>*      getLineInfo() const                     { return NULL; }
        virtual uint8_t                                                         getAlignment() const            { return 4; }
-       virtual WeakImportSetting                                       getImportWeakness() const       { return ObjectFile::Atom::kWeakUnset; }
        virtual void                                                            copyRawContent(uint8_t buffer[]) const;
-       virtual void                                                            writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
 
        virtual void                                                            setScope(Scope)                         { }
-       virtual void                                                            setImportWeakness(bool)         { }
 
 protected:
        friend class Reader;
        
                                                                                        Atom(Reader& owner, Segment& segment, const char* sectionName, const uint8_t fileContent[], uint64_t fileLength) 
-                                                                                               : fOwner(owner), fSegment(segment), fSectionName(sectionName), fFileContent(fileContent), fFileLength(fileLength) {}
+                                                                                               : fOwner(owner), fSegment(segment), fSectionName(sectionName), fFileContent(fileContent), fFileLength(fileLength) { setDontDeadStrip(); }
        virtual                                                                 ~Atom() {}
        
        Reader&                                                                 fOwner;
@@ -133,12 +129,6 @@ void Atom::copyRawContent(uint8_t buffer[]) const
        memcpy(buffer, fFileContent, fFileLength);
 }
 
-void Atom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
-       writer.write(0, fFileContent, fFileLength);
-}
-
-
 Reader* MakeReader(const char* segmentName, const char* sectionName, const char* path, const uint8_t fileContent[], uint64_t fileLength)
 {
        return new Reader(segmentName, sectionName, path, fileContent, fileLength);
index 73b49a56d48576007c9cc3eff2ee37119efb5a21..d5c7f4e50179cc066c22d797c89a5e07e8f33edd 100644 (file)
@@ -1,4 +1,5 @@
-/*
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
  * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
diff --git a/src/Writers/ExecutableFileMachO-all.cpp b/src/Writers/ExecutableFileMachO-all.cpp
deleted file mode 100644 (file)
index 661a3df..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
- */
-
-#include <stdint.h>
-#include <stddef.h>
-#include <fcntl.h>
-#include <sys/time.h>
-#include <mach-o/loader.h>
-#include <mach-o/nlist.h>
-#include <mach-o/reloc.h>
-#include <mach-o/ppc/reloc.h>
-#include <mach-o/stab.h>
-
-#include <vector>
-#include <algorithm>
-#include <map>
-#include <set>
-
-#include "ObjectFile.h"
-#include "ExecutableFile.h"
-#include "Options.h"
-
-// buiild Writer for -arch ppc64
-#undef MACHO_32_SAME_ENDIAN
-#undef MACHO_32_OPPOSITE_ENDIAN
-#undef MACHO_64_SAME_ENDIAN
-#undef MACHO_64_OPPOSITE_ENDIAN
-#if __ppc__ || __ppc64__
-       #define MACHO_64_SAME_ENDIAN
-#elif __i386__
-       #define MACHO_64_OPPOSITE_ENDIAN
-#else
-       #error unknown architecture
-#endif
-namespace ppc64 {
-       #undef  ARCH_PPC
-       #define ARCH_PPC64
-       #undef  ARCH_I386
-       #include "MachOAbstraction.h"
-       #include "ExecutableFileMachO.cpp"
-};
-
-// buiild Writer for -arch ppc
-#undef MACHO_32_SAME_ENDIAN
-#undef MACHO_32_OPPOSITE_ENDIAN
-#undef MACHO_64_SAME_ENDIAN
-#undef MACHO_64_OPPOSITE_ENDIAN
-#if __ppc__ || __ppc64__
-       #define MACHO_32_SAME_ENDIAN
-#elif __i386__
-       #define MACHO_32_OPPOSITE_ENDIAN
-#else
-       #error unknown architecture
-#endif
-namespace ppc {
-       #define ARCH_PPC
-       #undef  ARCH_PPC64
-       #undef  ARCH_I386
-       #include "MachOAbstraction.h"
-       #include "ExecutableFileMachO.cpp"
-};
-
-// buiild Writer for -arch i386
-#undef MACHO_32_SAME_ENDIAN
-#undef MACHO_32_OPPOSITE_ENDIAN
-#undef MACHO_64_SAME_ENDIAN
-#undef MACHO_64_OPPOSITE_ENDIAN
-#if __ppc__ || __ppc64__
-       #define MACHO_32_OPPOSITE_ENDIAN
-#elif __i386__
-       #define MACHO_32_SAME_ENDIAN
-#else
-       #error unknown architecture
-#endif
-#undef i386 // compiler sometimes #defines this
-namespace i386 {
-       #undef  ARCH_PPC
-       #undef  ARCH_PPC64
-       #define ARCH_I386
-       #include "MachOAbstraction.h"
-       #include "ExecutableFileMachO.cpp"
-};
-
-
diff --git a/src/Writers/ExecutableFileMachO-all.h b/src/Writers/ExecutableFileMachO-all.h
deleted file mode 100644 (file)
index 08d4ae6..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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 __EXECUTABLEFILEMACHO__
-#define __EXECUTABLEFILEMACHO__
-
-class Options;
-
-namespace ppc {
-       namespace ExecutableFileMachO {
-               extern class ExecutableFile::Writer* MakeWriter(const char* path, Options&, std::vector<ExecutableFile::DyLibUsed>&);
-       }
-};
-
-namespace ppc64 {
-       namespace ExecutableFileMachO {
-               extern class ExecutableFile::Writer* MakeWriter(const char* path, Options&, std::vector<ExecutableFile::DyLibUsed>&);
-       }
-};
-
-#undef i386 // compiler sometimes #defines this
-namespace i386 {
-       namespace ExecutableFileMachO {
-               extern class ExecutableFile::Writer* MakeWriter(const char* path, Options&, std::vector<ExecutableFile::DyLibUsed>&);
-       }
-};
-
-
-
-#endif // __EXECUTABLEFILEMACHO__
-
-
-
diff --git a/src/Writers/ExecutableFileMachO.cpp b/src/Writers/ExecutableFileMachO.cpp
deleted file mode 100644 (file)
index 90a9527..0000000
+++ /dev/null
@@ -1,2807 +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@
- */
-
-
-
-namespace ExecutableFileMachO {
-
-class Writer : public ExecutableFile::Writer
-{ 
-public:
-                                                               Writer(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries);
-       virtual                                         ~Writer();
-
-       virtual const char*                                                             getPath();
-       virtual std::vector<class ObjectFile::Atom*>&   getAtoms();
-       virtual std::vector<class ObjectFile::Atom*>*   getJustInTimeAtomsFor(const char* name);
-       virtual std::vector<ObjectFile::StabsInfo>*             getStabsDebugInfo();
-
-       virtual class ObjectFile::Atom*                                 getUndefinedProxyAtom(const char* name);
-       virtual void                                                                    write(std::vector<class ObjectFile::Atom*>& atoms, class ObjectFile::Atom* entryPointAtom);
-       
-private:
-       void                                            assignFileOffsets();
-       void                                            partitionIntoSections();
-       bool                                            addBranchIslands();
-       void                                            adjustLoadCommandsAndPadding();
-       void                                            createDynamicLinkerCommand();
-       void                                            createDylibCommands();
-       void                                            buildLinkEdit();
-       void                                            writeAtoms();
-       void                                            collectExportedAndImportedAndLocalAtoms();
-       void                                            setNlistRange(std::vector<class ObjectFile::Atom*>& atoms, uint32_t startIndex, uint32_t count);
-       void                                            buildSymbolTable();
-       void                                            setExportNlist(const ObjectFile::Atom* atom, macho_nlist* entry);
-       void                                            setImportNlist(const ObjectFile::Atom* atom, macho_nlist* entry);
-       void                                            setLocalNlist(const ObjectFile::Atom* atom, macho_nlist* entry);
-       uint64_t                                        getAtomLoadAddress(const ObjectFile::Atom* atom);
-       uint8_t                                         ordinalForLibrary(ObjectFile::Reader* file);
-       bool                                            shouldExport(ObjectFile::Atom& atom);
-       void                                            buildFixups();
-       void                                            adjustLinkEditSections();
-       void                                            buildObjectFileFixups();
-       void                                            buildExecutableFixups();
-       uint32_t                                        symbolIndex(ObjectFile::Atom& atom);
-       uint32_t                                        addRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref);
-       unsigned int                            collectStabs();
-       macho_uintptr_t                         valueForStab(const ObjectFile::StabsInfo& stab, const ObjectFile::Atom* atom);
-       void                                            addStabs(uint32_t startIndex, uint32_t count);
-
-       
-       class SectionInfo : public ObjectFile::Section {
-       public:
-                                                                                       SectionInfo();
-               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                                                            fAllNonLazyPointers;
-               bool                                                            fAllZeroFill;
-               bool                                                            fVirtualSection;
-       };
-       
-       class SegmentInfo 
-       {
-       public:
-                                                                                       SegmentInfo();
-               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;
-               bool                                                            fFixedAddress;
-       };
-
-       
-       struct DirectLibrary {
-               class ObjectFile::Reader*               fLibrary;
-               bool                                            fWeak;
-               bool                                            fReExport;      
-       };
-       
-       struct IndirectEntry {
-               uint32_t        indirectIndex;  
-               uint32_t        symbolIndex;
-       };
-
-       struct StabChunks {
-               ObjectFile::Atom*                                       fAtom;
-               ObjectFile::Reader*                                     fReader;
-               unsigned int                                            fReaderOrder;
-               unsigned int                                            fOrderInReader;
-               std::vector<ObjectFile::StabsInfo>*     fStabs;
-       };
-
-       static bool                                             stabChunkCompare(const StabChunks& lhs, const StabChunks& rhs);
-
-       friend class WriterAtom;
-       friend class PageZeroAtom;
-       friend class CustomStackAtom;
-       friend class MachHeaderAtom;
-       friend class SegmentLoadCommandsAtom;
-       friend class SymbolTableLoadCommandsAtom;
-       friend class ThreadsLoadCommandsAtom;
-       friend class DylibIDLoadCommandsAtom;
-       friend class RoutinesLoadCommandsAtom;
-       friend class DyldLoadCommandsAtom;
-       friend class LinkEditAtom;
-       friend class LocalRelocationsLinkEditAtom;
-       friend class ExternalRelocationsLinkEditAtom;
-       friend class SymbolTableLinkEditAtom;
-       friend class IndirectTableLinkEditAtom;
-       friend class StringsLinkEditAtom;
-
-       const char*                                                                             fFilePath;
-       Options&                                                                                fOptions;
-       int                                                                                             fFileDescriptor;
-       std::vector<class ObjectFile::Atom*>*                   fAllAtoms;
-       class SectionInfo*                                                              fLoadCommandsSection;
-       class SegmentInfo*                                                              fLoadCommandsSegment;
-       class SegmentLoadCommandsAtom*                                  fSegmentCommands;
-       class SymbolTableLoadCommandsAtom*                              fSymbolTableCommands;
-       class LoadCommandsPaddingAtom*                                  fHeaderPadding;
-       std::vector<class ObjectFile::Atom*>                    fWriterSynthesizedAtoms;
-       std::vector<SegmentInfo*>                                               fSegmentInfos;
-       class ObjectFile::Atom*                                                 fEntryPoint;
-       std::vector<DirectLibrary>                                              fDirectLibraries;
-       std::map<class ObjectFile::Reader*, uint32_t>   fLibraryToOrdinal;
-       std::vector<StabChunks>                                                 fStabChunks;
-       std::vector<class ObjectFile::Atom*>                    fExportedAtoms;
-       std::vector<class ObjectFile::Atom*>                    fImportedAtoms;
-       std::vector<class ObjectFile::Atom*>                    fLocalSymbolAtoms;      
-       LocalRelocationsLinkEditAtom*                                   fLocalRelocationsAtom;
-       ExternalRelocationsLinkEditAtom*                                fExternalRelocationsAtom;
-       SymbolTableLinkEditAtom*                                                fSymbolTableAtom;
-       IndirectTableLinkEditAtom*                                              fIndirectTableAtom;
-       StringsLinkEditAtom*                                                    fStringsAtom;
-       macho_nlist*                                                                    fSymbolTable;
-       //char*                                                                                 fStringPool;
-       //uint32_t                                                                              fStringPoolUsed;
-       //uint32_t                                                                              fStringPoolSize;
-       std::vector<macho_relocation_info>                              fInternalRelocs;
-       std::vector<macho_relocation_info>                              fExternalRelocs;
-       std::vector<IndirectEntry>                                              fIndirectSymbolTable;
-       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;   
-       bool                                                                                    fEmitVirtualSections;
-       bool                                                                                    fHasWeakExports;
-       bool                                                                                    fReferencesWeakImports;
-};
-
-
-class WriterAtom : public ObjectFile::Atom 
-{
-protected:
-       class Segment;
-public:
-       enum Kind { zeropage, machHeaderApp, machHeaderDylib, machHeaderBundle, machHeaderObject, loadCommands, undefinedProxy };
-                                                                                       WriterAtom(Writer& writer, class WriterAtom::Segment& segment) : fWriter(writer), fSegment(segment) {}
-                                                                                       
-       virtual ObjectFile::Reader*                             getFile() const                                 { return &fWriter; }
-       virtual const char*                                             getName() const                                 { return NULL; }
-       virtual const char*                                             getDisplayName() const                  { return this->getName(); }
-       virtual Scope                                                   getScope() const                                { return ObjectFile::Atom::scopeTranslationUnit; }
-       virtual bool                                                    isTentativeDefinition() const   { return false; }
-       virtual bool                                                    isWeakDefinition() const                { return false; }
-       virtual bool                                                    isCoalesableByName() const              { return false; }
-       virtual bool                                                    isCoalesableByValue() const             { return false; }
-       virtual bool                                                    isZeroFill() const                              { return false; }
-       virtual bool                                                    dontDeadStrip() const                   { return true; }
-       virtual bool                                                    dontStripName() const                   { return false; }
-       virtual bool                                                    isImportProxy() 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 bool                                                    requiresFollowOnAtom() const    { return false; } 
-       virtual ObjectFile::Atom&                               getFollowOnAtom() const                 { return *((ObjectFile::Atom*)NULL); }
-       virtual std::vector<ObjectFile::StabsInfo>*     getStabsDebugInfo() const       { return NULL; }
-       virtual uint8_t                                                 getAlignment() const                    { return 2; }
-       virtual WeakImportSetting                               getImportWeakness() const               { return Atom::kWeakUnset; }
-       virtual void                                                    copyRawContent(uint8_t buffer[]) const { throw "don't use copyRawContent"; }
-       virtual void                                                    setScope(Scope)                                 { }
-       virtual void                                                    setImportWeakness(bool weakImport) { }
-
-
-protected:
-       virtual                                                                 ~WriterAtom() {}
-       
-       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; }
-       private:
-               const char*                                     fName;
-               const bool                                      fReadable;
-               const bool                                      fWritable;
-               const bool                                      fExecutable;
-               const bool                                      fFixedAddress;
-       };
-       
-       static std::vector<ObjectFile::Reference*>      fgEmptyReferenceList;
-       static Segment                                                          fgTextSegment;
-       static Segment                                                          fgPageZeroSegment;
-       static Segment                                                          fgLinkEditSegment;
-       static Segment                                                          fgStackSegment;
-       
-       
-       Writer&                                                                 fWriter;
-       Segment&                                                                fSegment;
-};
-
-
-WriterAtom::Segment                                            WriterAtom::fgPageZeroSegment("__PAGEZERO", false, false, false, true);
-WriterAtom::Segment                                            WriterAtom::fgTextSegment("__TEXT", true, false, true, false);
-WriterAtom::Segment                                            WriterAtom::fgLinkEditSegment("__LINKEDIT", true, false, false, false);
-WriterAtom::Segment                                            WriterAtom::fgStackSegment("__UNIXSTACK", true, true, false, true);
-std::vector<ObjectFile::Reference*>            WriterAtom::fgEmptyReferenceList;
-
-class PageZeroAtom : public WriterAtom 
-{
-public:
-                                                                                       PageZeroAtom(Writer& writer) : WriterAtom(writer, fgPageZeroSegment) {}
-       virtual const char*                                             getDisplayName() const  { return "page zero content"; }
-       virtual bool                                                    isZeroFill() const              { return true; }
-       virtual uint64_t                                                getSize() const                 { return fWriter.fOptions.zeroPageSize(); }
-       virtual const char*                                             getSectionName() const  { return "._zeropage"; }
-       virtual uint8_t                                                 getAlignment() const    { return 12; }
-       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const {}
-};
-
-class MachHeaderAtom : public WriterAtom 
-{
-public:
-                                                                                       MachHeaderAtom(Writer& writer)  : WriterAtom(writer, fgTextSegment) {}
-       virtual const char*                                             getName() const;
-       virtual const char*                                             getDisplayName() const;
-       virtual Scope                                                   getScope() const;
-       virtual bool                                                    dontStripName() const;
-       virtual uint64_t                                                getSize() const;
-       virtual uint8_t                                                 getAlignment() const            { return 12; }
-       virtual const char*                                             getSectionName() const          { return "._mach_header"; }
-       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-};
-
-class CustomStackAtom : public WriterAtom 
-{
-public:
-                                                                                       CustomStackAtom(Writer& 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 uint8_t                                                 getAlignment() const    { return 12; }
-       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const {}
-};
-
-class SegmentLoadCommandsAtom : public WriterAtom 
-{
-public:
-                                                                                       SegmentLoadCommandsAtom(Writer& writer)  : WriterAtom(writer, fgTextSegment), fCommandCount(0), fSize(0) { writer.fSegmentCommands = this; }
-       virtual const char*                                             getDisplayName() const  { return "segment load commands"; }
-       virtual uint64_t                                                getSize() const                 { return fSize; }
-       virtual uint8_t                                                 getAlignment() const    { return 2; }
-       virtual const char*                                             getSectionName() const  { return "._load_commands"; }
-       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-       
-       void                                                                    computeSize();
-       void                                                                    setup();
-       unsigned int                                                    commandCount()                  { return fCommandCount; }
-       void                                                                    assignFileOffsets();
-private:
-       unsigned int                                                    fCommandCount;
-       uint32_t                                                                fSize;
-};
-
-class SymbolTableLoadCommandsAtom : public WriterAtom 
-{
-public:
-                                                                                       SymbolTableLoadCommandsAtom(Writer&);
-       virtual const char*                                             getDisplayName() const { return "symbol table load commands"; }
-       virtual uint64_t                                                getSize() const;
-       virtual uint8_t                                                 getAlignment() const    { return 2; }
-       virtual const char*                                             getSectionName() const  { return "._load_commands"; }
-       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-       
-private:
-       macho_symtab_command                                    fSymbolTable;
-       macho_dysymtab_command                                  fDynamicSymbolTable;
-};
-
-class ThreadsLoadCommandsAtom : public WriterAtom 
-{
-public:
-                                                                                       ThreadsLoadCommandsAtom(Writer& writer) : WriterAtom(writer, fgTextSegment) {}
-       virtual const char*                                             getDisplayName() const { return "thread load commands"; }
-       virtual uint64_t                                                getSize() const;
-       virtual uint8_t                                                 getAlignment() const    { return 2; }
-       virtual const char*                                             getSectionName() const  { return "._load_commands"; }
-       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-private:
-       uint8_t*                                                                fBuffer;
-       uint32_t                                                                fBufferSize;
-};
-
-class DyldLoadCommandsAtom : public WriterAtom 
-{
-public:
-                                                                                       DyldLoadCommandsAtom(Writer& writer)  : WriterAtom(writer, fgTextSegment) {}
-       virtual const char*                                             getDisplayName() const  { return "dyld load command"; }
-       virtual uint64_t                                                getSize() const;
-       virtual uint8_t                                                 getAlignment() const    { return 2; }
-       virtual const char*                                             getSectionName() const  { return "._load_commands"; }
-       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-};
-
-class DylibLoadCommandsAtom : public WriterAtom 
-{
-public:
-                                                                                       DylibLoadCommandsAtom(Writer& writer, ExecutableFile::DyLibUsed& info)  : WriterAtom(writer, fgTextSegment), fInfo(info) {}
-       virtual const char*                                             getDisplayName() const  { return "dylib load command"; }
-       virtual uint64_t                                                getSize() const;
-       virtual uint8_t                                                 getAlignment() const    { return 2; }
-       virtual const char*                                             getSectionName() const  { return "._load_commands"; }
-       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-private:
-       ExecutableFile::DyLibUsed&                              fInfo;
-};
-
-class DylibIDLoadCommandsAtom : public WriterAtom 
-{
-public:
-                                                                                       DylibIDLoadCommandsAtom(Writer& writer) : WriterAtom(writer, fgTextSegment) {}
-       virtual const char*                                             getDisplayName() const { return "dylib ID load command"; }
-       virtual uint64_t                                                getSize() const;
-       virtual uint8_t                                                 getAlignment() const    { return 2; }
-       virtual const char*                                             getSectionName() const  { return "._load_commands"; }
-       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-};
-
-class RoutinesLoadCommandsAtom : public WriterAtom 
-{
-public:
-                                                                                       RoutinesLoadCommandsAtom(Writer& writer) : WriterAtom(writer, fgTextSegment) {}
-       virtual const char*                                             getDisplayName() const { return "routines load command"; }
-       virtual uint64_t                                                getSize() const;
-       virtual uint8_t                                                 getAlignment() const    { return 2; }
-       virtual const char*                                             getSectionName() const  { return "._load_commands"; }
-       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-};
-
-class SubUmbrellaLoadCommandsAtom : public WriterAtom 
-{
-public:
-                                                                                       SubUmbrellaLoadCommandsAtom(Writer& writer, const char* name)  : WriterAtom(writer, fgTextSegment), fName(name) {}
-       virtual const char*                                             getDisplayName() const  { return "sub-umbrella load command"; }
-       virtual uint64_t                                                getSize() const;
-       virtual uint8_t                                                 getAlignment() const    { return 2; }
-       virtual const char*                                             getSectionName() const  { return "._load_commands"; }
-       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-private:
-       const char*                                                             fName;
-};
-
-class SubLibraryLoadCommandsAtom : public WriterAtom 
-{
-public:
-                                                                                       SubLibraryLoadCommandsAtom(Writer& writer,  const char* nameStart, int nameLen)  
-                                                                                                       : WriterAtom(writer, fgTextSegment), fNameStart(nameStart), fNameLength(nameLen) {}
-       virtual const char*                                             getDisplayName() const  { return "sub-library load command"; }
-       virtual uint64_t                                                getSize() const;
-       virtual uint8_t                                                 getAlignment() const    { return 2; }
-       virtual const char*                                             getSectionName() const  { return "._load_commands"; }
-       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-private:
-       const char*                                                             fNameStart;
-       int                                                                             fNameLength;
-};
-
-class UmbrellaLoadCommandsAtom : public WriterAtom 
-{
-public:
-                                                                                       UmbrellaLoadCommandsAtom(Writer& writer, const char* name)  
-                                                                                                       : WriterAtom(writer, fgTextSegment), fName(name) {}
-       virtual const char*                                             getDisplayName() const  { return "umbrella load command"; }
-       virtual uint64_t                                                getSize() const;
-       virtual uint8_t                                                 getAlignment() const    { return 2; }
-       virtual const char*                                             getSectionName() const  { return "._load_commands"; }
-       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-private:
-       const char*                                                             fName;
-};
-
-class LoadCommandsPaddingAtom : public WriterAtom 
-{
-public:
-                                                                                       LoadCommandsPaddingAtom(Writer& writer)  
-                                                                                                       : WriterAtom(writer, fgTextSegment), fSize(0) {}
-       virtual const char*                                             getDisplayName() const  { return "header padding"; }
-       virtual uint64_t                                                getSize() const;
-       virtual uint8_t                                                 getAlignment() const    { return 2; }
-       virtual const char*                                             getSectionName() const  { return "._load_cmds_pad"; }
-       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-       
-       void                                                                    setSize(uint64_t newSize) { fSize = newSize; }
-private:
-       uint64_t                                                                fSize;
-};
-
-class LinkEditAtom : public WriterAtom 
-{
-public:
-                                                                                       LinkEditAtom(Writer& writer) : WriterAtom(writer, fgLinkEditSegment) {}
-       uint64_t                                                                getFileOffset() const;
-};
-
-class LocalRelocationsLinkEditAtom : public LinkEditAtom 
-{
-public:
-                                                                                       LocalRelocationsLinkEditAtom(Writer& writer) : LinkEditAtom(writer) { }
-       virtual const char*                                             getDisplayName() const  { return "local relocations"; }
-       virtual uint64_t                                                getSize() const;
-       virtual uint8_t                                                 getAlignment() const    { return 3; }
-       virtual const char*                                             getSectionName() const  { return "._local_relocs"; }
-       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-};
-
-class SymbolTableLinkEditAtom : public LinkEditAtom 
-{
-public:
-                                                                                       SymbolTableLinkEditAtom(Writer& writer) : LinkEditAtom(writer) { }
-       virtual const char*                                             getDisplayName() const  { return "symbol table"; }
-       virtual uint64_t                                                getSize() const;
-       virtual uint8_t                                                 getAlignment() const    { return 2; }
-       virtual const char*                                             getSectionName() const  { return "._symbol_table"; }
-       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-};
-
-class ExternalRelocationsLinkEditAtom : public LinkEditAtom 
-{
-public:
-                                                                                       ExternalRelocationsLinkEditAtom(Writer& writer) : LinkEditAtom(writer) { }
-       virtual const char*                                             getDisplayName() const  { return "external relocations"; }
-       virtual uint64_t                                                getSize() const;
-       virtual uint8_t                                                 getAlignment() const    { return 3; }
-       virtual const char*                                             getSectionName() const  { return "._extern_relocs"; }
-       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-};
-
-class IndirectTableLinkEditAtom : public LinkEditAtom 
-{
-public:
-                                                                                       IndirectTableLinkEditAtom(Writer& writer) : LinkEditAtom(writer) { }
-       virtual const char*                                             getDisplayName() const  { return "indirect symbol table"; }
-       virtual uint64_t                                                getSize() const;
-       virtual uint8_t                                                 getAlignment() const    { return 2; }
-       virtual const char*                                             getSectionName() const  { return "._indirect_syms"; }
-       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-};
-
-class StringsLinkEditAtom : public LinkEditAtom 
-{
-public:
-                                                                                       StringsLinkEditAtom(Writer& writer);
-       virtual const char*                                             getDisplayName() const  { return "string pool"; }
-       virtual uint64_t                                                getSize() const;
-       virtual uint8_t                                                 getAlignment() const    { return 2; }
-       virtual const char*                                             getSectionName() const  { return "._string_pool"; }
-       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-       
-       int32_t                                                                 add(const char* name);
-       int32_t                                                                 emptyString();
-       
-private:
-       enum { kBufferSize = 0x01000000 };
-
-       std::vector<char*>                                              fFullBuffers;
-       char*                                                                   fCurrentBuffer;
-       uint32_t                                                                fCurrentBufferUsed;
-};
-
-
-
-class UndefinedSymbolProxyAtom : public WriterAtom 
-{
-public:
-                                                                                       UndefinedSymbolProxyAtom(Writer& writer, const char* name) : WriterAtom(writer, fgLinkEditSegment), fName(name), fWeakImportSetting(Atom::kWeakUnset) {}
-       virtual const char*                                             getName() const                         { return fName; }
-       virtual Scope                                                   getScope() const                        { return ObjectFile::Atom::scopeGlobal; }
-       virtual uint64_t                                                getSize() const                         { return 0; }
-       virtual bool                                                    isWeakDefinition() const        { return true; }
-       virtual bool                                                    isImportProxy() const           { return true; }
-       virtual const char*                                             getSectionName() const          { return "._imports"; }
-       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const {}
-       virtual WeakImportSetting                               getImportWeakness() const       { return fWeakImportSetting; }
-       virtual void                                                    setImportWeakness(bool weakImport) { fWeakImportSetting = weakImport ? kWeakImport : kNonWeakImport; }
-private:
-       const char*                                                             fName;
-       WeakImportSetting                                               fWeakImportSetting;
-};
-
-#if defined(ARCH_PPC) || defined(ARCH_PPC64) 
-class BranchIslandAtom : public WriterAtom 
-{
-public:
-                                                                                       BranchIslandAtom(Writer& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset);
-       virtual const char*                                             getName() const                         { return fName; }
-       virtual Scope                                                   getScope() const                        { return ObjectFile::Atom::scopeLinkageUnit; }
-       virtual uint64_t                                                getSize() const                         { return 4; }
-       virtual const char*                                             getSectionName() const          { return "__text"; }
-       virtual void                                                    writeContent(bool finalLinkedImage, ObjectFile::ContentWriter&) const;
-private:
-       const char*                                                             fName;
-       ObjectFile::Atom&                                               fTarget;
-       uint32_t                                                                fTargetOffset;
-};
-#endif
-
-struct ExportSorter
-{
-     bool operator()(ObjectFile::Atom* left, ObjectFile::Atom* right)
-     {
-          return (strcmp(left->getName(), right->getName()) < 0);
-     }
-};
-
-
-ExecutableFile::Writer* MakeWriter(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries)
-{
-       return new Writer(path, options, dynamicLibraries);
-}
-
-Writer::SectionInfo::SectionInfo()
- : fFileOffset(0), fSize(0), fRelocCount(0), fRelocOffset(0), fIndirectSymbolOffset(0), fAlignment(0),
-       fAllLazyPointers(false), fAllNonLazyPointers(false), fAllZeroFill(false), fVirtualSection(false)
-{
-       fSegmentName[0] = '\0';
-       fSectionName[0] = '\0';
-}
-       
-Writer::SegmentInfo::SegmentInfo()
- : fInitProtection(0), fMaxProtection(0), fFileOffset(0), fFileSize(0), fBaseAddress(0), fSize(0), fFixedAddress(false)
-{
-       fName[0] = '\0';
-}
-
-
-Writer::Writer(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries)
- : ExecutableFile::Writer(dynamicLibraries), fFilePath(strdup(path)), fOptions(options), fLoadCommandsSection(NULL), 
-       fLoadCommandsSegment(NULL),
-       //fStringPool(NULL), fStringPoolUsed(0), fStringPoolSize(0), 
-       fEmitVirtualSections(false), fHasWeakExports(false), fReferencesWeakImports(false)
-{
-       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 writeable 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);
-       fFileDescriptor = open(fFilePath, O_CREAT | O_WRONLY | O_TRUNC, permissions);   
-       if ( fFileDescriptor == -1 ) {
-               throw "can't open file for writing";
-       }
-
-       switch ( fOptions.outputKind() ) {
-               case Options::kDynamicExecutable:
-               case Options::kStaticExecutable:
-                       fWriterSynthesizedAtoms.push_back(new PageZeroAtom(*this));
-                       fWriterSynthesizedAtoms.push_back(new MachHeaderAtom(*this));
-                       fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom(*this));
-                       fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom(*this));
-                       if ( fOptions.outputKind() == Options::kDynamicExecutable )
-                               fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom(*this));
-                       fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom(*this));
-                       if ( fOptions.hasCustomStack() )
-                               fWriterSynthesizedAtoms.push_back(new CustomStackAtom(*this));
-                       fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom(*this));
-                       fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom(*this));
-                       fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom(*this));
-                       fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom(*this));
-                       fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom(*this));
-                       fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom(*this));
-                       break;
-               case Options::kDynamicLibrary:
-               case Options::kDynamicBundle:
-               case Options::kObjectFile:
-                       fWriterSynthesizedAtoms.push_back(new MachHeaderAtom(*this));
-                       fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom(*this));
-                       if ( fOptions.outputKind() == Options::kDynamicLibrary ) {
-                               fWriterSynthesizedAtoms.push_back(new DylibIDLoadCommandsAtom(*this));
-                               if ( fOptions.initFunctionName() != NULL )
-                                       fWriterSynthesizedAtoms.push_back(new RoutinesLoadCommandsAtom(*this));
-                       }
-                       fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom(*this));
-                       fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom(*this));
-                       fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom(*this));
-                       fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom(*this));
-                       fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom(*this));
-                       fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom(*this));
-                       fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom(*this));
-                       break;
-               case Options::kDyld:
-                       fWriterSynthesizedAtoms.push_back(new MachHeaderAtom(*this));
-                       fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom(*this));
-                       fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom(*this));
-                       fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom(*this));
-                       fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom(*this));
-                       fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom(*this));
-                       fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom(*this));
-                       fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom(*this));
-                       fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom(*this));
-                       fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom(*this));
-                       fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom(*this));
-                       break;
-       }
-       
-       // add extra commmands
-       uint8_t ordinal = 1;
-       switch ( fOptions.outputKind() ) {
-               case Options::kDynamicExecutable:
-               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];
-                                       if ( dylibInfo.indirect ) {
-                                               // find ordinal of direct reader
-                                               if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace ) {
-                                                       bool found = false;
-                                                       for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
-                                                               if ( it->first == dylibInfo.directReader ) {
-                                                                       //fprintf(stderr, "ordinal %d for indirect %s\n", it->second, dylibInfo.reader->getPath());
-                                                                       fLibraryToOrdinal[dylibInfo.reader] = it->second;
-                                                                       found = true;
-                                                                       break;
-                                                               }
-                                                       }
-                                                       if ( ! found ) 
-                                                               fprintf(stderr, "ld64 warning: ordinal not found for %s, parent %s\n", dylibInfo.reader->getPath(), dylibInfo.directReader != NULL ? dylibInfo.directReader->getPath() : NULL);
-                                               }
-                                       }
-                                       else {
-                                               // see if a DylibLoadCommandsAtom has already been created for this install path
-                                               bool newDylib = true;
-                                               const char* dylibInstallPath = dylibInfo.reader->getInstallPath();
-                                               if ( dylibInfo.options.fInstallPathOverride != NULL ) 
-                                                       dylibInstallPath = dylibInfo.options.fInstallPathOverride;
-                                               for (unsigned int seenLib=0; seenLib < i; ++seenLib) {
-                                                       ExecutableFile::DyLibUsed& seenDylibInfo = dynamicLibraries[seenLib];
-                                                       if ( !seenDylibInfo.indirect ) {
-                                                               const char* seenDylibInstallPath = seenDylibInfo.reader->getInstallPath();
-                                                               if ( seenDylibInfo.options.fInstallPathOverride != NULL ) 
-                                                                       seenDylibInstallPath = dylibInfo.options.fInstallPathOverride;
-                                                               if ( strcmp(seenDylibInstallPath, dylibInstallPath) == 0 ) {
-                                                                       fLibraryToOrdinal[dylibInfo.reader] = fLibraryToOrdinal[seenDylibInfo.reader];
-                                                                       newDylib = false;
-                                                                       break;
-                                                               }
-                                                       }
-                                               }
-                                               
-                                               if ( newDylib ) {
-                                                       // assign new ordinal and check for other paired load commands
-                                                       fLibraryToOrdinal[dylibInfo.reader] = ordinal++;
-                                                       fWriterSynthesizedAtoms.push_back(new DylibLoadCommandsAtom(*this, dylibInfo));
-                                                       if ( dylibInfo.options.fReExport ) {
-                                                               // 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(*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(*this, nameStart, len));
-                                                               }
-                                                       }
-                                               }
-                                       }
-                               }
-                               // add umbrella command if needed
-                               if ( fOptions.umbrellaName() != NULL ) {
-                                       fWriterSynthesizedAtoms.push_back(new UmbrellaLoadCommandsAtom(*this, fOptions.umbrellaName()));
-                               }
-                       }
-                       break;
-               case Options::kStaticExecutable:
-               case Options::kObjectFile:
-               case Options::kDyld:
-                       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());
-       //}
-}
-
-Writer::~Writer()
-{
-       if ( fFilePath != NULL )
-               free((void*)fFilePath);
-       if ( fSymbolTable != NULL )
-               delete [] fSymbolTable;
-       //if ( fStringPool != NULL )
-       //      delete [] fStringPool;
-}
-
-const char*     Writer::getPath()
-{
-       return fFilePath;
-}
-
-
-std::vector<class ObjectFile::Atom*>& Writer::getAtoms()
-{
-       return fWriterSynthesizedAtoms;
-}
-
-std::vector<class ObjectFile::Atom*>* Writer::getJustInTimeAtomsFor(const char* name)
-{
-       return NULL;
-}
-
-std::vector<ObjectFile::StabsInfo>*    Writer::getStabsDebugInfo()
-{
-       return NULL;
-}
-
-ObjectFile::Atom* Writer::getUndefinedProxyAtom(const char* name)
-{
-       if ( (fOptions.outputKind() == Options::kObjectFile)
-               || (fOptions.undefinedTreatment() != Options::kUndefinedError) )
-               return new UndefinedSymbolProxyAtom(*this, name);
-       else
-               return NULL;
-}
-
-uint8_t Writer::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";
-}
-
-void Writer::write(std::vector<class ObjectFile::Atom*>& atoms, class ObjectFile::Atom* entryPointAtom)
-{
-       fAllAtoms =  &atoms;
-       fEntryPoint = entryPointAtom;
-
-       // 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();
-
-       // build symbol table and relocations
-       buildLinkEdit();
-       
-       // write everything
-       writeAtoms();
-}
-
-void Writer::buildLinkEdit()
-{
-       this->collectExportedAndImportedAndLocalAtoms();
-       this->buildSymbolTable();
-       this->buildFixups();
-       this->adjustLinkEditSections();
-}
-
-
-
-uint64_t Writer::getAtomLoadAddress(const ObjectFile::Atom* atom)
-{
-       return atom->getAddress();
-//     SectionInfo* info = (SectionInfo*)atom->getSection();
-//     return info->getBaseAddress() + atom->getSectionOffset();
-}
-
-void Writer::setExportNlist(const ObjectFile::Atom* atom, macho_nlist* entry)
-{
-       // set n_type
-       entry->set_n_type(N_EXT | N_SECT);
-       if ( (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit) && fOptions.keepPrivateExterns() && (fOptions.outputKind() == Options::kObjectFile) )
-               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 ( (fOptions.outputKind() == Options::kDynamicExecutable) && (sectionIndex==0) && atom->dontStripName())
-               entry->set_n_type(N_EXT | N_ABS);
-
-       // set n_desc
-       uint16_t desc = 0;
-       if ( atom->dontStripName() )
-               desc |= REFERENCED_DYNAMICALLY;
-       if ( atom->isWeakDefinition() && (strcmp(atom->getSectionName(), "__common") != 0) ) {
-               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 )
-       entry->set_n_value(this->getAtomLoadAddress(atom));
-}
-
-void Writer::setImportNlist(const ObjectFile::Atom* atom, macho_nlist* entry)
-{
-       // set n_type
-       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 )
-               desc = REFERENCE_FLAG_UNDEFINED_LAZY; // FIXME
-               try {
-                       uint8_t ordinal = this->ordinalForLibrary(atom->getFile());
-                       SET_LIBRARY_ORDINAL(desc, ordinal);
-               }
-               catch (const char* msg) {
-                       throwf("%s %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath());
-               }
-       }
-       if ( atom->dontStripName() )
-               desc |= REFERENCED_DYNAMICALLY;
-       // an import proxy is always weak (overridden by definition in .o files)
-       // so we ask its reader if the exported symbol in its dylib is weak
-       if ( ( fOptions.outputKind() != Options::kObjectFile) && atom->getFile()->isDefinitionWeak(*atom) ) {
-               desc |= N_REF_TO_WEAK;
-               fReferencesWeakImports = true;
-       }
-       // set weak_import attribute
-       if ( atom->getImportWeakness() == ObjectFile::Atom::kWeakImport ) 
-               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());
-}
-
-void Writer::setLocalNlist(const ObjectFile::Atom* atom, macho_nlist* entry)
-{
-       // set n_type
-       uint8_t type = N_SECT;
-       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->isWeakDefinition() && (strcmp(atom->getSectionName(), "__common") != 0) ) // commons on not weak
-               desc |= N_WEAK_DEF;
-       entry->set_n_desc(desc);
-       
-       // 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));
-}
-
-
-void Writer::setNlistRange(std::vector<class ObjectFile::Atom*>& atoms, uint32_t startIndex, uint32_t count)
-{
-       macho_nlist* entry = &fSymbolTable[startIndex];
-       for (uint32_t i=0; i < count; ++i, ++entry) {
-               ObjectFile::Atom* atom = atoms[i];
-               entry->set_n_strx(this->fStringsAtom->add(atom->getName()));
-               if ( &atoms == &fExportedAtoms ) {
-                       this->setExportNlist(atom, entry);
-               }
-               else if ( &atoms == &fImportedAtoms ) {
-                       this->setImportNlist(atom, entry);
-               }
-               else {
-                       this->setLocalNlist(atom, entry);
-               }
-       }
-}
-
-void Writer::buildSymbolTable()
-{
-       fSymbolTableStabsStartIndex             = 0;
-       fSymbolTableStabsCount                  = this->collectStabs();
-       fSymbolTableLocalStartIndex             = fSymbolTableStabsStartIndex + fSymbolTableStabsCount;
-       fSymbolTableLocalCount                  = fLocalSymbolAtoms.size();
-       fSymbolTableExportStartIndex    = fSymbolTableLocalStartIndex + fSymbolTableLocalCount;
-       fSymbolTableExportCount                 = fExportedAtoms.size();
-       fSymbolTableImportStartIndex    = fSymbolTableExportStartIndex + fSymbolTableExportCount;
-       fSymbolTableImportCount                 = fImportedAtoms.size();
-       
-       // allocate symbol table
-       fSymbolTableCount = fSymbolTableStabsCount + fSymbolTableLocalCount + fSymbolTableExportCount + fSymbolTableImportCount;
-       fSymbolTable = new macho_nlist[fSymbolTableCount];
-       
-       // fill in symbol table and string pool (do stabs last so strings are at end of pool)
-       setNlistRange(fLocalSymbolAtoms, fSymbolTableLocalStartIndex,  fSymbolTableLocalCount);
-       setNlistRange(fExportedAtoms,    fSymbolTableExportStartIndex, fSymbolTableExportCount);
-       setNlistRange(fImportedAtoms,    fSymbolTableImportStartIndex, fSymbolTableImportCount);
-       addStabs(fSymbolTableStabsStartIndex, fSymbolTableStabsCount);
-}
-
-
-
-bool Writer::shouldExport(ObjectFile::Atom& atom)
-{
-       switch ( atom.getScope() ) {
-               case ObjectFile::Atom::scopeGlobal:
-                       return true;
-               case ObjectFile::Atom::scopeLinkageUnit:
-                       return ( fOptions.keepPrivateExterns() && (fOptions.outputKind() == Options::kObjectFile) );
-               default:
-                       return false;
-       }
-}
-
-void Writer::collectExportedAndImportedAndLocalAtoms()
-{
-       const int atomCount = fAllAtoms->size();
-       for (int i=0; i < atomCount; ++i) {
-               ObjectFile::Atom* atom = (*fAllAtoms)[i];
-               // only named atoms go in symbol table
-               if ( atom->getName() != NULL ) {
-                       // put atom into correct bucket: imports, exports, locals
-                       //printf("collectExportedAndImportedAndLocalAtoms() name=%s\n", atom->getDisplayName());
-                       if ( atom->isImportProxy() || ((fOptions.outputKind() == Options::kObjectFile) && (strcmp(atom->getSectionName(), "__common") == 0)) )
-                               fImportedAtoms.push_back(atom);
-                       else if ( this->shouldExport(*atom) )
-                               fExportedAtoms.push_back(atom);
-                       else if ( !fOptions.stripLocalSymbols() )
-                               fLocalSymbolAtoms.push_back(atom);
-               }
-       }
-       
-       // sort exported atoms by name
-       std::sort(fExportedAtoms.begin(), fExportedAtoms.end(), ExportSorter());
-}
-
-
-bool Writer::stabChunkCompare(const struct StabChunks& lhs, const struct StabChunks& rhs)
-{
-       if ( lhs.fReader != rhs.fReader ) {
-               return lhs.fReaderOrder < rhs.fReaderOrder;
-       }
-       return lhs.fOrderInReader < rhs.fOrderInReader;
-}
-
-unsigned int Writer::collectStabs()
-{      
-       unsigned int count = 0;
-       
-       // collect all stabs chunks
-       std::set<ObjectFile::Reader*> seenReaders;
-       std::map<ObjectFile::Reader*, unsigned int> readerOrdinals;
-       const int atomCount = fAllAtoms->size();
-       for (int i=0; i < atomCount; ++i) {
-               ObjectFile::Atom* atom = (*fAllAtoms)[i];
-               ObjectFile::Reader* atomsReader = atom->getFile();
-               unsigned int readerOrder = 0;
-               if ( atomsReader != NULL ) {
-                       std::map<ObjectFile::Reader*, unsigned int>::iterator pos = readerOrdinals.find(atomsReader);
-                       if ( pos == readerOrdinals.end() ) {
-                               readerOrder = readerOrdinals.size();
-                               readerOrdinals[atomsReader] = readerOrder;
-                               std::vector<ObjectFile::StabsInfo>* readerStabs = atomsReader->getStabsDebugInfo();
-                               if ( readerStabs != NULL ) {
-                                       StabChunks chunk;
-                                       chunk.fAtom                             = NULL;
-                                       chunk.fReader                   = atomsReader;
-                                       chunk.fReaderOrder              = readerOrder;
-                                       chunk.fOrderInReader    = 0;
-                                       chunk.fStabs                    = readerStabs;
-                                       fStabChunks.push_back(chunk);
-                                       count += readerStabs->size() + 1; // extra one is for trailing N_SO
-                               }
-                       }
-                       else {
-                               readerOrder = pos->second;
-                       }
-               }
-               std::vector<ObjectFile::StabsInfo>* atomStabs = atom->getStabsDebugInfo();
-               if ( atomStabs != NULL ) {
-                       StabChunks chunk;
-                       chunk.fAtom                             = atom;
-                       chunk.fReader                   = atomsReader;
-                       chunk.fReaderOrder              = readerOrder;
-                       chunk.fOrderInReader    = atom->getSortOrder();
-                       chunk.fStabs                    = atomStabs;
-                       fStabChunks.push_back(chunk);
-                       count += atomStabs->size();
-               }
-       }
-       
-       // sort stabs: group by .o file 
-       std::sort(fStabChunks.begin(), fStabChunks.end(), stabChunkCompare);
-       
-       //fprintf(stderr, "Sorted stabs:\n");
-       //for (std::vector<StabChunks>::iterator it=fStabChunks.begin(); it != fStabChunks.end(); it++) {
-       //      ObjectFile::Atom* atom = (*it).fAtom;
-       //      if ( atom != NULL )
-       //              fprintf(stderr, "\t%s\n", (*it).fAtom->getDisplayName());
-       //      else
-       //              fprintf(stderr, "\t%s\n", (*it).fReader->getPath());
-       //}
-       
-       return count;
-}
-
-macho_uintptr_t Writer::valueForStab(const ObjectFile::StabsInfo& stab, const ObjectFile::Atom* atom)
-{
-       switch ( stab.type ) {
-               case N_FUN:
-                       if ( stab.other == 0 )
-                               break;
-                       // end of function N_FUN has size (not address) so should not be adjusted
-                       // fall through
-               case N_BNSYM:
-               case N_ENSYM:
-               case N_LBRAC:
-               case N_RBRAC:
-               case N_SLINE:
-               case N_STSYM:
-               case N_LCSYM:
-                       // all these stab types need their value changed from an offset in the atom to an address
-                       if ( atom != NULL )
-                               return getAtomLoadAddress(atom) + stab.atomOffset;
-       }
-       return stab.atomOffset;
-}
-
-void Writer::addStabs(uint32_t startIndex, uint32_t count)
-{
-       macho_nlist* entry = &fSymbolTable[startIndex];
-       const int chunkCount = fStabChunks.size();
-       for (int i=0; i < chunkCount; ++i ) {
-               const StabChunks& chunk = fStabChunks[i];
-               const int stabCount = chunk.fStabs->size();
-               for (int j=0; j < stabCount; ++j ) {
-                       const ObjectFile::StabsInfo& stab = (*chunk.fStabs)[j];
-                       entry->set_n_type(stab.type);
-                       entry->set_n_sect(stab.other);
-                       entry->set_n_desc(stab.desc);
-                       entry->set_n_value(valueForStab(stab, chunk.fAtom));
-                       entry->set_n_strx(this->fStringsAtom->add(stab.string));
-                       ++entry;
-               }       
-               if ( (i == chunkCount-1) || (fStabChunks[i+1].fReader != chunk.fReader) ) {
-                       // need to add empty SO at end of each file
-                       entry->set_n_type(N_SO);
-                       entry->set_n_sect(1);
-                       entry->set_n_desc(0);
-                       entry->set_n_value(0);
-                       entry->set_n_strx(this->fStringsAtom->emptyString());
-                       ++entry;
-               }
-       }
-}
-
-
-
-uint32_t Writer::symbolIndex(ObjectFile::Atom& atom)
-{
-       // search imports
-       int i = 0;
-       for(std::vector<ObjectFile::Atom*>::iterator it=fImportedAtoms.begin(); it != fImportedAtoms.end(); ++it) {
-               if ( &atom == *it )
-                       return i + fSymbolTableImportStartIndex;
-               ++i;
-       }
-       
-       // search locals
-       i = 0;
-       for(std::vector<ObjectFile::Atom*>::iterator it=fLocalSymbolAtoms.begin(); it != fLocalSymbolAtoms.end(); ++it) {
-               if ( &atom == *it )
-                       return i + fSymbolTableLocalStartIndex;
-               ++i;
-       }
-       
-       // search exports
-       i = 0;
-       for(std::vector<ObjectFile::Atom*>::iterator it=fExportedAtoms.begin(); it != fExportedAtoms.end(); ++it) {
-               if ( &atom == *it )
-                       return i + fSymbolTableExportStartIndex;
-               ++i;
-       }
-       
-       fprintf(stderr, "symbolIndex(%s)\n", atom.getDisplayName());
-       fprintf(stderr, "from %s\n", atom.getFile()->getPath());
-       throw "atom not found";
-}
-
-void Writer::buildFixups()
-{
-       if ( fOptions.outputKind() == Options::kObjectFile )
-               this->buildObjectFileFixups();
-       else
-               this->buildExecutableFixups();
-}
-
-uint32_t Writer::addRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
-{
-       ObjectFile::Atom& target = ref->getTarget();
-       bool isExtern = target.isImportProxy() || ( strcmp(target.getSectionName(), "__common") == 0 );
-       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 reloc1;
-       macho_relocation_info reloc2;
-       macho_scattered_relocation_info* sreloc1 = (macho_scattered_relocation_info*)&reloc1;
-       macho_scattered_relocation_info* sreloc2 = (macho_scattered_relocation_info*)&reloc2;
-       
-       switch ( ref->getKind() ) {
-               case ObjectFile::Reference::noFixUp:
-                       return 0;
-                       
-               case ObjectFile::Reference::pointer:
-                       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(macho_relocation_info::pointer_length); 
-                       reloc1.set_r_extern(isExtern);
-                       reloc1.set_r_type(GENERIC_RELOC_VANILLA);
-                       fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
-                       return 1;
-                       
-               case ObjectFile::Reference::ppcFixupBranch24:
-                       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());
-                       }
-                       fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
-                       return 1;
-               
-               case ObjectFile::Reference::ppcFixupBranch14:
-                       reloc1.set_r_address(address);
-                       reloc1.set_r_symbolnum(sectionNum);
-                       reloc1.set_r_pcrel(true);
-                       reloc1.set_r_length(2); 
-                       reloc1.set_r_extern(false);
-                       reloc1.set_r_type(PPC_RELOC_BR14);
-                       fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
-                       return 1;
-
-               case ObjectFile::Reference::ppcFixupPicBaseLow14:
-               case ObjectFile::Reference::ppcFixupPicBaseLow16:
-                       {
-                               macho_uintptr_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
-                               macho_uintptr_t toAddr = target.getAddress() + ref->getTargetOffset();
-                               uint32_t overflow = 0;
-                               if ( ((toAddr-fromAddr) & 0x00008000) != 0 )
-                                       overflow = 1;
-                               sreloc1->set_r_scattered(true);
-                               sreloc1->set_r_pcrel(false);
-                               sreloc1->set_r_length(2); 
-                               if ( ref->getKind() == ObjectFile::Reference::ppcFixupPicBaseLow16 )
-                                       sreloc1->set_r_type(PPC_RELOC_LO16_SECTDIFF);
-                               else
-                                       sreloc1->set_r_type(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));
-                               sreloc2->set_r_value(fromAddr);
-                               fInternalRelocs.insert(fInternalRelocs.begin(), reloc2);
-                               fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
-                               return 2;
-                       }
-               
-               case ObjectFile::Reference::ppcFixupPicBaseHigh16:
-                       {
-                               macho_uintptr_t fromAddr = atom->getAddress() + ref->getFromTargetOffset();
-                               macho_uintptr_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);
-                               fInternalRelocs.insert(fInternalRelocs.begin(), reloc2);
-                               fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
-                               return 2;
-                       }
-                       
-               case ObjectFile::Reference::ppcFixupAbsLow14:
-               case ObjectFile::Reference::ppcFixupAbsLow16:
-                       {
-                               macho_uintptr_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);
-                                       if ( ref->getKind() == ObjectFile::Reference::ppcFixupAbsLow16 )
-                                               reloc1.set_r_type(PPC_RELOC_LO16);
-                                       else
-                                               reloc1.set_r_type(PPC_RELOC_LO14);
-                               }
-                               else {
-                                       sreloc1->set_r_scattered(true);
-                                       sreloc1->set_r_pcrel(false);
-                                       sreloc1->set_r_length(2); 
-                                       if ( ref->getKind() == ObjectFile::Reference::ppcFixupAbsLow16 )
-                                               sreloc1->set_r_type(PPC_RELOC_LO16);
-                                       else
-                                               sreloc1->set_r_type(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);
-                               fInternalRelocs.insert(fInternalRelocs.begin(), reloc2);
-                               fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
-                               return 2;
-                       }
-                       
-               case ObjectFile::Reference::ppcFixupAbsHigh16:
-                       {
-                               macho_uintptr_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);
-                               fInternalRelocs.insert(fInternalRelocs.begin(), reloc2);
-                               fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
-                               return 2;
-                       }
-               
-               case ObjectFile::Reference::ppcFixupAbsHigh16AddLow:
-                       {
-                               macho_uintptr_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);
-                               fInternalRelocs.insert(fInternalRelocs.begin(), reloc2);
-                               fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
-                               return 2;
-                       }
-               
-               case ObjectFile::Reference::pointer32Difference:
-               case ObjectFile::Reference::pointer64Difference:
-                       {
-                               macho_uintptr_t toAddr = target.getAddress() + ref->getTargetOffset();
-                               macho_uintptr_t fromAddr = ref->getFromTarget().getAddress() + ref->getFromTargetOffset();
-                               sreloc1->set_r_scattered(true);
-                               sreloc1->set_r_pcrel(false);
-                               if ( ref->getKind() == ObjectFile::Reference::pointer64Difference )
-                                       sreloc1->set_r_length(3); 
-                               else
-                                       sreloc1->set_r_length(2); 
-                               if ( ref->getTargetOffset() != 0 )
-                                       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(toAddr);
-                               sreloc2->set_r_scattered(true);
-                               sreloc2->set_r_pcrel(false);
-                               sreloc2->set_r_length(macho_relocation_info::pointer_length); 
-                               sreloc2->set_r_type(PPC_RELOC_PAIR);
-                               sreloc2->set_r_address(0);
-                               sreloc2->set_r_value(fromAddr);
-                               fInternalRelocs.insert(fInternalRelocs.begin(), reloc2);
-                               fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
-                               return 2;
-                       }
-                       
-               case ObjectFile::Reference::x86FixupBranch32:
-                       reloc1.set_r_address(address);
-                       reloc1.set_r_symbolnum(sectionNum);
-                       reloc1.set_r_pcrel(true);
-                       reloc1.set_r_length(2); 
-                       reloc1.set_r_extern(false);
-                       reloc1.set_r_type(GENERIC_RELOC_VANILLA);
-                       fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
-                       return 1;
-               
-       }
-       return 0;
-}
-
-
-void Writer::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];
-                       std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
-                       if ( ! curSection->fAllZeroFill ) {
-                               if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers )
-                                       curSection->fIndirectSymbolOffset = fIndirectSymbolTable.size();
-                               curSection->fRelocOffset = relocIndex;
-                               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();
-                                       for (int l=0; l < refCount; ++l) {
-                                               ObjectFile::Reference* ref = refs[l];
-                                               if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers ) {
-                                                       uint32_t offsetInSection = atom->getSectionOffset();
-                                                       uint32_t indexInSection = offsetInSection / sizeof(macho_uintptr_t);    
-                                                       uint32_t undefinedSymbolIndex = this->symbolIndex(ref->getTarget());
-                                                       uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
-                                                       IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
-                                                       //printf("fIndirectSymbolTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, ref->getTarget().getName(), atom->getSize());
-                                                       fIndirectSymbolTable.push_back(entry);
-                                                       if ( curSection->fAllLazyPointers ) {
-                                                               ObjectFile::Atom& target = ref->getTarget();
-                                                               ObjectFile::Atom& fromTarget = ref->getFromTarget();
-                                                               if ( &fromTarget == NULL ) {
-                                                                       fprintf(stderr, "lazy pointer %s missing initial binding\n", atom->getDisplayName());
-                                                               }
-                                                               else {
-                                                                       bool isExtern = target.isImportProxy();
-                                                                       uint32_t symbolIndex = 0;
-                                                                       if ( isExtern ) 
-                                                                               symbolIndex = this->symbolIndex(target);
-                                                                       uint32_t sectionNum = target.getSection()->getIndex();
-                                                                       uint32_t address = atom->getSectionOffset();
-                                                                       macho_relocation_info reloc1;
-                                                                       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(macho_relocation_info::pointer_length); 
-                                                                       reloc1.set_r_extern(isExtern);
-                                                                       reloc1.set_r_type(GENERIC_RELOC_VANILLA);
-                                                                       fInternalRelocs.insert(fInternalRelocs.begin(), reloc1);
-                                                                       ++relocIndex;
-                                                               }
-                                                       }
-                                               }
-                                               else {
-                                                       relocIndex += this->addRelocs(atom, ref);
-                                               }
-                                       }
-                               }
-                               curSection->fRelocCount = relocIndex - curSection->fRelocOffset;
-                       }
-               }
-       }
-       
-       // now reverse reloc entries
-       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; 
-               }
-       }
-       
-}
-
-
-void Writer::buildExecutableFixups()
-{
-       const bool slideable = (fOptions.outputKind() != Options::kDynamicExecutable) && (fOptions.outputKind() != Options::kStaticExecutable);
-       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];
-                       std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
-                       if ( ! curSection->fAllZeroFill ) {
-                               if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers )
-                                       curSection->fIndirectSymbolOffset = fIndirectSymbolTable.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();
-                                       //printf("atom %s has %d references\n", atom->getDisplayName(), refCount);
-                                       for (int l=0; l < refCount; ++l) {
-                                               ObjectFile::Reference* ref = refs[l];
-                                               if ( curSection->fAllNonLazyPointers || curSection->fAllLazyPointers ) {
-                                                       // if atom is in (non)lazy_pointer section, this is encoded as an indirect symbol
-                                                       if ( atom->getSize() != sizeof(macho_uintptr_t) ) {
-                                                               printf("wrong size pointer atom %s from file %s\n", atom->getDisplayName(), atom->getFile()->getPath());
-                                                       }
-                                                       uint32_t offsetInSection = atom->getSectionOffset();
-                                                       uint32_t indexInSection = offsetInSection / sizeof(macho_uintptr_t);    
-                                                       uint32_t undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
-                                                       //fprintf(stderr,"indirect pointer atom %p %s section offset = %d\n", atom, atom->getDisplayName(), offsetInSection);
-                                                       if ( ref->getTarget().isImportProxy() 
-                                                         || ref->getTarget().isWeakDefinition() 
-                                                         || (fOptions.interposable() && fOptions.shouldExport(ref->getTarget().getName()))
-                                                         || (fOptions.nameSpace() == Options::kFlatNameSpace) 
-                                                         || (fOptions.nameSpace() == Options::kForceFlatNameSpace) ) {
-                                                               undefinedSymbolIndex = this->symbolIndex(ref->getTarget());
-                                                       }
-                                                       uint32_t indirectTableIndex = indexInSection + curSection->fIndirectSymbolOffset;
-                                                       IndirectEntry entry = { indirectTableIndex, undefinedSymbolIndex };
-                                                       //fprintf(stderr,"fIndirectSymbolTable.add(%d-%d => 0x%X-%s), size=%lld\n", indexInSection, indirectTableIndex, undefinedSymbolIndex, ref->getTarget().getName(), atom->getSize());
-                                                       fIndirectSymbolTable.push_back(entry);
-                                                       if ( slideable && curSection->fAllLazyPointers ) {
-                                                               // if this is a dylib/bundle, need vanilla internal relocation to fix up binding handler if image slides
-                                                               macho_relocation_info pblaReloc;
-                                                               SectionInfo* sectInfo = (SectionInfo*)ref->getFromTarget().getSection();
-                                                               uint32_t sectionNum = sectInfo->getIndex();
-                                                               pblaReloc.set_r_address(atom->getAddress()-fOptions.baseAddress());
-                                                               pblaReloc.set_r_symbolnum(sectionNum); 
-                                                               pblaReloc.set_r_pcrel(false);
-                                                               pblaReloc.set_r_length(macho_relocation_info::pointer_length); 
-                                                               pblaReloc.set_r_extern(false);
-                                                               pblaReloc.set_r_type(GENERIC_RELOC_VANILLA);
-                                                               fInternalRelocs.push_back(pblaReloc);
-                                                       }
-                                               }
-                                               else if ( ref->requiresRuntimeFixUp(slideable) ) {
-                                                       if ( ! atom->getSegment().isContentWritable() )
-                                                               throwf("relocations in read-only segments not supported. %s in %s reference to %s", atom->getDisplayName(), atom->getFile()->getPath(), ref->getTarget().getDisplayName());
-                                                       if ( ref->getTarget().isImportProxy() ) {
-                                                               // if import is to antoher dylib, this is encoded as an external relocation
-                                                               macho_relocation_info externalReloc;
-                                                               externalReloc.set_r_address(atom->getAddress()+ref->getFixUpOffset()-fOptions.baseAddress());
-                                                               externalReloc.set_r_symbolnum(this->symbolIndex(ref->getTarget()));
-                                                               externalReloc.set_r_pcrel(false);
-                                                               externalReloc.set_r_length(macho_relocation_info::pointer_length); 
-                                                               externalReloc.set_r_extern(true);
-                                                               externalReloc.set_r_type(GENERIC_RELOC_VANILLA);
-                                                               fExternalRelocs.push_back(externalReloc);
-                                                       }
-                                                       else {
-                                                               // if this is a dylib/bundle, need fix-up encoded as an internal relocation
-                                                               macho_relocation_info 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(atom->getAddress()+ref->getFixUpOffset()-fOptions.baseAddress());
-                                                               internalReloc.set_r_symbolnum(sectionNum);
-                                                               internalReloc.set_r_pcrel(false);
-                                                               internalReloc.set_r_length(macho_relocation_info::pointer_length); 
-                                                               internalReloc.set_r_extern(false);
-                                                               internalReloc.set_r_type(GENERIC_RELOC_VANILLA);
-                                                               fInternalRelocs.push_back(internalReloc);
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               }
-       }
-}
-
-class ContentWriter : public ObjectFile::ContentWriter
-{
-public:
-                                       ContentWriter(int fd, uint64_t fileOffset) : fFileDescriptor(fd), fFileOffset(fileOffset) {}
-       virtual void    write(uint64_t atomOffset, const void* buffer, uint64_t size) {
-               ::pwrite(fFileDescriptor, buffer, size, fFileOffset+atomOffset);
-       }
-private:
-       int                     fFileDescriptor;
-       uint64_t        fFileOffset;
-};
-
-
-void Writer::writeAtoms()
-{
-       const bool requireAllFixUps = (fOptions.outputKind() != Options::kObjectFile);
-
-       std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
-       const int segCount = segmentInfos.size();
-       for(int i=0; i < segCount; ++i) {
-               SegmentInfo* curSegment = segmentInfos[i];
-               bool isText = ((curSegment->fInitProtection & VM_PROT_EXECUTE) != 0);
-               std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
-               const int sectionCount = sectionInfos.size();
-               for(int j=0; j < sectionCount; ++j) {
-                       SectionInfo* curSection = sectionInfos[j];
-                       std::vector<ObjectFile::Atom*>& sectionAtoms = curSection->fAtoms;
-                       //printf("writing %d atoms for section %s\n", (int)sectionAtoms.size(), curSection->fSectionName);
-                       if ( ! curSection->fAllZeroFill ) {
-                               const int atomCount = sectionAtoms.size();
-                               uint32_t end = curSection->fFileOffset;
-                               for (int k=0; k < atomCount; ++k) {
-                                       ObjectFile::Atom* atom = sectionAtoms[k];
-                                       if ( !atom->isImportProxy() ) {
-                                               uint32_t offset = curSection->fFileOffset + atom->getSectionOffset();
-                                               if ( isText && (offset != end) ) {
-                                                       // fill gaps with no-ops
-                       #if defined(ARCH_PPC) || defined(ARCH_PPC64) 
-                                                       uint32_t ppcNop;
-                                                       OSWriteBigInt32(&ppcNop, 0, 0x60000000);
-                                                       for (uint32_t p=end; p < offset; p += 4)
-                                                               ::pwrite(fFileDescriptor, &ppcNop, 4, p);
-                       #else  defined(ARCH_I386)
-                                                       uint8_t x86Nop = 0x90;
-                                                       for (uint32_t p=end; p < offset; ++p)
-                                                               ::pwrite(fFileDescriptor, &x86Nop, 1, p);
-                       #endif
-                                               }
-                                               end = offset+atom->getSize();
-                                               //fprintf(stderr, "writing 0x%08X -> 0x%08X, atom %s\n", offset, end, atom->getDisplayName());
-                                               ContentWriter writer(fFileDescriptor, offset);
-                                               atom->writeContent(requireAllFixUps, writer);
-                                       }
-                               }
-                       }
-               }
-       }
-}      
-
-
-void Writer::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 = NULL;
-       SectionInfo* currentSectionInfo = NULL;
-       SegmentInfo* currentSegmentInfo = NULL;
-       unsigned int sectionIndex = 1;
-       for (unsigned int i=0; i < fAllAtoms->size(); ++i) {
-               ObjectFile::Atom* atom = (*fAllAtoms)[i];
-               if ( atom->getSection() != curSection ) {
-                       if ( oneSegmentCommand ) {
-                               if ( currentSegmentInfo == NULL ) {
-                                       currentSegmentInfo = new SegmentInfo();
-                                       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();
-                               currentSectionInfo->fAllZeroFill = atom->isZeroFill();
-                               currentSectionInfo->fVirtualSection = ( currentSectionInfo->fSectionName[0] == '.');
-                               if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
-                                       currentSectionInfo->setIndex(sectionIndex++);
-                               currentSegmentInfo->fSections.push_back(currentSectionInfo);
-                       }
-                       else {
-                               if ( (currentSegmentInfo == NULL) || (strcmp(currentSegmentInfo->fName, atom->getSegment().getName()) != 0) ) {
-                                       currentSegmentInfo = new SegmentInfo();
-                                       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;
-                                       currentSegmentInfo->fInitProtection = initprot;
-                                       if ( initprot == 0 )
-                                               currentSegmentInfo->fMaxProtection = 0;  // pagezero should have maxprot==initprot==0
-                                       else
-                                               currentSegmentInfo->fMaxProtection = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
-                                       currentSegmentInfo->fBaseAddress = atom->getSegment().getBaseAddress();
-                                       currentSegmentInfo->fFixedAddress = atom->getSegment().hasFixedAddress();
-                                       this->fSegmentInfos.push_back(currentSegmentInfo);
-                               }
-                               currentSectionInfo = new SectionInfo();
-                               strcpy(currentSectionInfo->fSectionName, atom->getSectionName());
-                               strcpy(currentSectionInfo->fSegmentName, atom->getSegment().getName());
-                               currentSectionInfo->fAlignment = atom->getAlignment();
-                               // 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);
-                       }
-                       if ( (strcmp(currentSectionInfo->fSegmentName, "__TEXT") == 0) && (strcmp(currentSectionInfo->fSectionName, "._load_commands") == 0) ) {
-                               fLoadCommandsSection = currentSectionInfo;
-                               fLoadCommandsSegment = currentSegmentInfo;
-                       }
-                       if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_symbol_ptr") == 0) )
-                               currentSectionInfo->fAllLazyPointers = true;
-                       if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__la_sym_ptr2") == 0) )
-                               currentSectionInfo->fAllLazyPointers = true;
-                       if ( (strcmp(currentSectionInfo->fSegmentName, "__DATA") == 0) && (strcmp(currentSectionInfo->fSectionName, "__nl_symbol_ptr") == 0) )
-                               currentSectionInfo->fAllNonLazyPointers = true;
-                       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();
-               if ( currentSectionInfo->fAlignment < atomAlign )
-                       currentSectionInfo->fAlignment = atomAlign;
-               // calculate section offset for this atom
-               uint64_t offset = currentSectionInfo->fSize;
-               uint64_t alignment = 1 << atomAlign;
-               offset = ( (offset+alignment-1) & (-alignment) );
-               atom->setSectionOffset(offset);
-               currentSectionInfo->fSize = offset + atom->getSize();
-               // add atom to section vector
-               currentSectionInfo->fAtoms.push_back(atom);
-       }
-}
-
-
-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 );
-       }
-};
-
-//
-// 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 hoping to the target.
-//
-// Branch Island Algorithm
-//
-// If the __TEXT segment < 16MB, then no branch islands needed
-// Otherwise, every 15MB into the __TEXT segment is 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
-// 15MB which means the region would have to be 1MB (256K islands)
-// before any branches could be pushed out of range.
-//
-bool Writer::addBranchIslands()
-{
-       bool result = false;
-#if defined(ARCH_PPC) || defined(ARCH_PPC64) 
-       // Can only possibly need branch islands if __TEXT segment > 16M
-       if ( fLoadCommandsSegment->fSize > 16000000 ) {
-               const uint32_t kBetweenRegions = 15000000; // place regions of islands every 15MB 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;
-               }
-               const int kIslandRegionsCount = textSection->fSize / kBetweenRegions; 
-               typedef std::map<TargetAndOffset,ObjectFile::Atom*, TargetAndOffsetComparor> AtomToIsland;
-               AtomToIsland regionsMap[kIslandRegionsCount];
-               std::vector<ObjectFile::Atom*> regionsIslands[kIslandRegionsCount];
-               unsigned int islandCount = 0;
-               
-               // 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 ( ref->getKind() == ObjectFile::Reference::ppcFixupBranch24 ) {
-                                       ObjectFile::Atom& target = ref->getTarget();
-                                       int64_t srcAddr = atom->getAddress() + ref->getFixUpOffset();
-                                       int64_t dstAddr = target.getAddress() + ref->getTargetOffset();
-                                       int64_t displacement = dstAddr - srcAddr;
-                                       const int64_t kFifteenMegLimit = kBetweenRegions;
-                                       if ( (displacement > kFifteenMegLimit) || (displacement < (-kFifteenMegLimit)) ) {
-                                               for (int i=0; i < kIslandRegionsCount; ++i) {
-                                                       AtomToIsland* region=&regionsMap[i];
-                                                       int64_t islandRegionAddr = kBetweenRegions * (i+1);
-                                                       if ( ((srcAddr < islandRegionAddr) && (dstAddr > islandRegionAddr)) 
-                                                          ||((dstAddr < islandRegionAddr) && (srcAddr > islandRegionAddr)) ) {
-                                                               TargetAndOffset islandTarget = { &target, ref->getTargetOffset() };
-                                                               AtomToIsland::iterator pos = region->find(islandTarget);
-                                                               if ( pos == region->end() ) {
-                                                                       BranchIslandAtom* island = new BranchIslandAtom(*this, target.getDisplayName(), i, target, ref->getTargetOffset());
-                                                                       (*region)[islandTarget] = island;
-                                                                       regionsIslands[i].push_back(island);
-                                                                       ++islandCount;
-                                                                       ref->setTarget(*island, 0);
-                                                               }
-                                                               else {
-                                                                       ref->setTarget(*(pos->second), 0);
-                                                               }
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               }
-               
-               // insert islands into __text section and adjust section offsets
-               if ( islandCount > 0 ) {
-                       std::vector<ObjectFile::Atom*> newAtomList;
-                       newAtomList.reserve(textSection->fAtoms.size()+islandCount);
-                       uint64_t islandRegionAddr = kBetweenRegions;
-                       int regionIndex = 0;
-                       uint64_t sectionOffset = 0;
-                       for (std::vector<ObjectFile::Atom*>::iterator it=textSection->fAtoms.begin(); it != textSection->fAtoms.end(); it++) {
-                               ObjectFile::Atom* atom = *it;
-                               newAtomList.push_back(atom);
-                               if ( atom->getAddress() > islandRegionAddr ) {
-                                       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);
-                                               islandAtom->setSection(textSection);
-                                               uint64_t alignment = 1 << (islandAtom->getAlignment());
-                                               sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
-                                               islandAtom->setSectionOffset(sectionOffset);
-                                               sectionOffset += islandAtom->getSize();
-                                       }
-                                       ++regionIndex;
-                                       islandRegionAddr += kBetweenRegions;
-                               }
-                               uint64_t alignment = 1 << (atom->getAlignment());
-                               sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
-                               atom->setSectionOffset(sectionOffset);
-                               sectionOffset += atom->getSize();
-                       }
-                       textSection->fAtoms = newAtomList;
-                       textSection->fSize = sectionOffset;
-                       result = true;
-               }
-               
-       }
-#endif
-       return result;
-}
-
-
-void Writer::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();
-               offset = ( (offset+alignment-1) & (-alignment) );
-               atom->setSectionOffset(offset);
-               offset += atom->getSize();
-               fLoadCommandsSection->fSize = offset;
-       }
-       
-       std::vector<SectionInfo*>& sectionInfos = fLoadCommandsSegment->fSections;
-       const int sectionCount = sectionInfos.size();
-       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
-               uint32_t totalSizeOfHeaderAndLoadCommands = 0;
-               for(int j=0; j < sectionCount; ++j) {
-                       SectionInfo* curSection = sectionInfos[j];
-                       totalSizeOfHeaderAndLoadCommands += curSection->fSize;
-                       if ( strcmp(curSection->fSectionName, fHeaderPadding->getSectionName()) == 0 )
-                               break;
-               }
-               paddingSize = 4096 - (totalSizeOfHeaderAndLoadCommands % 4096);
-       }
-       else {
-               // calculate max padding to keep segment size same, but all free space at end of load commands
-               uint64_t totalSize = 0;
-               uint64_t worstCaseAlignmentPadding = 0;
-               for(int j=0; j < sectionCount; ++j) {
-                       SectionInfo* curSection = sectionInfos[j];
-                       totalSize += curSection->fSize;
-                       if ( j != 0 ) // don't count aligment of mach_header which is page-aligned
-                               worstCaseAlignmentPadding += (1 << curSection->fAlignment) - 1;
-               }
-               uint64_t segmentSize = ((totalSize+worstCaseAlignmentPadding+4095) & (-4096));
-               // don't know exactly how it will layout, but we can inflate padding atom this big and still keep aligment constraints
-               paddingSize = segmentSize - totalSize;
-               
-               // if command line requires more padding than this
-               if ( paddingSize < fOptions.minimumHeaderPad() ) {
-                       int extraPages = (fOptions.minimumHeaderPad() - paddingSize + 4095)/4096;
-                       paddingSize += extraPages * 4096;
-               }
-       }
-       
-       // 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;
-       }
-}
-
-// assign file offsets and logical address to all segments
-void Writer::assignFileOffsets()
-{
-       bool haveFixedSegments = false;
-       uint64_t fileOffset = 0;
-       uint64_t nextContiguousAddress = 0;
-       bool baseAddressUsed = false; 
-       std::vector<SegmentInfo*>& segmentInfos = fSegmentInfos;
-       const int segCount = segmentInfos.size();
-       for(int i=0; i < segCount; ++i) {
-               SegmentInfo* curSegment = segmentInfos[i];
-               fileOffset = (fileOffset+4095) & (-4096);
-               curSegment->fFileOffset = fileOffset;
-               if ( curSegment->fFixedAddress ) {
-                       // segment has fixed address already set
-                       haveFixedSegments = true;
-               }
-               else {
-                       // segment uses next address
-                       if ( !baseAddressUsed ) {
-                               baseAddressUsed = true;
-                               if ( fOptions.baseAddress() != 0 ) 
-                                       nextContiguousAddress = fOptions.baseAddress();
-                       }
-                       curSegment->fBaseAddress = nextContiguousAddress;
-               }
-               uint64_t address = curSegment->fBaseAddress;
-               std::vector<SectionInfo*>& sectionInfos = curSegment->fSections;
-               const int sectionCount = sectionInfos.size();
-               for(int j=0; j < sectionCount; ++j) {
-                       SectionInfo* curSection = sectionInfos[j];
-                       uint64_t alignment = 1 << curSection->fAlignment;
-                       fileOffset = ( (fileOffset+alignment-1) & (-alignment) );
-                       address    = ( (address+alignment-1)    & (-alignment) );
-                       curSection->fFileOffset = fileOffset;
-                       curSection->setBaseAddress(address);
-                       //printf("assignFileOffsets(): setBaseAddress(%s, 0x%08llX)\n", curSection->fSectionName, address);
-                       curSegment->fSize = curSection->getBaseAddress() + curSection->fSize - curSegment->fBaseAddress;
-                       if ( (fOptions.outputKind() != Options::kObjectFile) || ! curSection->fVirtualSection )
-                               address += curSection->fSize;
-                       if ( !curSection->fAllZeroFill ) {
-                               curSegment->fFileSize = curSegment->fSize;
-                               fileOffset += curSection->fSize;
-                       }
-               }
-               // page align segment size
-               curSegment->fFileSize = (curSegment->fFileSize+4095) & (-4096);
-               curSegment->fSize         = (curSegment->fSize+4095) & (-4096);
-               if ( curSegment->fBaseAddress == nextContiguousAddress )
-                       nextContiguousAddress = (curSegment->fBaseAddress+curSegment->fSize+4095) & (-4096);
-       }
-       
-       // check for segment overlaps
-       if ( haveFixedSegments ) {
-               for(int i=0; i < segCount; ++i) {
-                       SegmentInfo* segment1 = segmentInfos[i];
-                       for(int j=0; j < segCount; ++j) {
-                               if ( i != j ) {
-                                       SegmentInfo* segment2 = segmentInfos[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 {
-                                                       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);
-                                       }
-                               }
-                       }
-               }
-       }
-}
-
-void Writer::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 sectionCount = lastSeg->fSections.size();
-       uint64_t fileOffset = lastSeg->fSections[firstLinkEditSectionIndex]->fFileOffset;
-       uint64_t address = lastSeg->fSections[firstLinkEditSectionIndex]->getBaseAddress();
-       for (unsigned int i=firstLinkEditSectionIndex; i < sectionCount; ++i) {
-               std::vector<class ObjectFile::Atom*>& atoms = lastSeg->fSections[i]->fAtoms;
-               const unsigned int atomCount = atoms.size();
-               uint64_t sectionOffset = 0;
-               lastSeg->fSections[i]->fFileOffset = fileOffset;
-               lastSeg->fSections[i]->setBaseAddress(address);
-               for (unsigned int j=0; j < atomCount; ++j) {
-                       ObjectFile::Atom* atom = atoms[j];
-                       uint64_t alignment = 1 << atom->getAlignment();
-                       sectionOffset = ( (sectionOffset+alignment-1) & (-alignment) );
-                       atom->setSectionOffset(sectionOffset);
-                       sectionOffset += atom->getSize();
-               }
-               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);
-       }
-}
-
-
-ObjectFile::Atom::Scope MachHeaderAtom::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:
-                       return ObjectFile::Atom::scopeLinkageUnit; 
-       }
-       throw "unknown header type";
-}
-
-bool MachHeaderAtom::dontStripName() const
-{ 
-       switch ( fWriter.fOptions.outputKind() ) {
-               case Options::kDynamicExecutable:
-               case Options::kStaticExecutable:
-                       return true; 
-               case Options::kDynamicLibrary:
-               case Options::kDynamicBundle:
-               case Options::kDyld:
-               case Options::kObjectFile:
-                       return false; 
-       }
-       throw "unknown header type";
-}
-
-const char* MachHeaderAtom::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:
-                       return NULL;
-               case Options::kDyld:
-                       return "__mh_dylinker_header";
-       }
-       throw "unknown header type";
-}
-
-const char* MachHeaderAtom::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:
-                       return "mach header";
-       }
-       throw "unknown header type";
-}
-
-uint64_t MachHeaderAtom::getSize() const
-{
-       return macho_header::size;
-}
-
-void MachHeaderAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
-       macho_header mh;
-
-       // 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;
-       }
-
-       // get flags
-       uint32_t flags = 0;
-       if ( fWriter.fOptions.outputKind() == Options::kObjectFile ) {
-               flags = MH_SUBSECTIONS_VIA_SYMBOLS;
-       }
-       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;
-               }
-               if ( fWriter.fHasWeakExports ) 
-                       flags |= MH_WEAK_DEFINES;
-               if ( fWriter.fReferencesWeakImports || fWriter.fHasWeakExports )
-                       flags |= MH_BINDS_TO_WEAK;
-       }
-       
-       // get commands info
-       uint32_t commandsSize = 0;
-       uint32_t commandsCount = 0;
-       
-       std::vector<class ObjectFile::Atom*>& loadCommandAtoms = fWriter.fLoadCommandsSection->fAtoms;
-       const unsigned int atomCount = loadCommandAtoms.size();
-       for (unsigned int i=0; i < atomCount; ++i) {
-               ObjectFile::Atom* atom = loadCommandAtoms[i];
-               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 += 2;
-               else
-                       ++commandsCount;
-       }
-       
-       // fill out mach_header
-       mh.set_magic(macho_header::magic_value);
-       mh.set_cputype(fWriter.fOptions.architecture());
-#if defined(ARCH_PPC) || defined(ARCH_PPC64) 
-       mh.set_cpusubtype(CPU_SUBTYPE_POWERPC_ALL);
-#elif defined(ARCH_I386)
-       mh.set_cpusubtype(CPU_SUBTYPE_I386_ALL);
-#else
-       #error unknown architecture
-#endif
-       mh.set_filetype(fileType);
-       mh.set_ncmds(commandsCount);            
-       mh.set_sizeofcmds(commandsSize);        
-       mh.set_flags(flags);
-       mh.set_reserved();
-       
-       // write it
-       writer.write(0, &mh, macho_header::size);
-}
-
-
-CustomStackAtom::CustomStackAtom(Writer& writer) 
- : WriterAtom(writer, fgStackSegment)
-{
-#if defined(ARCH_PPC) || defined(ARCH_PPC64) || defined(ARCH_I386)
-       // stack grows down for these architectures
-       fgStackSegment.setBaseAddress(writer.fOptions.customStackAddr() - writer.fOptions.customStackSize());
-#else
-       #error unknown architecture
-#endif
-}
-
-
-void SegmentLoadCommandsAtom::computeSize() 
-{
-       uint64_t size = 0;
-       std::vector<Writer::SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
-       const int segCount = segmentInfos.size();
-       for(int i=0; i < segCount; ++i) {
-               size += macho_segment_command::size;
-               std::vector<Writer::SectionInfo*>& sectionInfos = segmentInfos[i]->fSections;
-               const int sectionCount = sectionInfos.size();           
-               for(int j=0; j < sectionCount; ++j) {
-                       if ( fWriter.fEmitVirtualSections || ! sectionInfos[j]->fVirtualSection )
-                               size += macho_section::content_size;
-               }
-       }
-       fSize = size;
-       fCommandCount = segCount;
-}
-
-
-
-void SegmentLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
-       uint64_t size = this->getSize();
-       uint8_t buffer[size];
-       const bool oneSegment =( fWriter.fOptions.outputKind() == Options::kObjectFile );
-       bzero(buffer, fSize);
-       uint8_t* p = buffer;
-       std::vector<Writer::SegmentInfo*>& segmentInfos = fWriter.fSegmentInfos;
-       const int segCount = segmentInfos.size();
-       for(int i=0; i < segCount; ++i) {
-               Writer::SegmentInfo* segInfo = segmentInfos[i];
-               const int sectionCount = segInfo->fSections.size();
-               macho_segment_command* cmd = (macho_segment_command*)p;
-               cmd->set_cmd(macho_segment_command::command);
-               cmd->set_segname(segInfo->fName);
-               cmd->set_vmaddr(segInfo->fBaseAddress);
-               cmd->set_vmsize(segInfo->fSize);
-               cmd->set_fileoff(segInfo->fFileOffset);
-               cmd->set_filesize(segInfo->fFileSize);
-               cmd->set_maxprot(segInfo->fMaxProtection);
-               cmd->set_initprot(segInfo->fInitProtection);
-               // add sections array
-               macho_section* const sections = (macho_section*)&p[macho_segment_command::size];
-               unsigned int sectionsEmitted = 0;
-               for (int j=0; j < sectionCount; ++j) {
-                       Writer::SectionInfo* sectInfo = segInfo->fSections[j];
-                       if ( fWriter.fEmitVirtualSections || !sectInfo->fVirtualSection ) {
-                               macho_section* sect = &sections[sectionsEmitted++];
-                               if ( oneSegment ) {
-                                       // .o files have weird segment range
-                                       if ( sectionsEmitted == 1 ) {
-                                               cmd->set_vmaddr(sectInfo->getBaseAddress());
-                                               cmd->set_fileoff(sectInfo->fFileOffset);
-                                               cmd->set_filesize(segInfo->fFileSize-sectInfo->fFileOffset);
-                                       }
-                                       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 * macho_relocation_info::size + fWriter.fLocalRelocationsAtom->getFileOffset());
-                                       sect->set_nreloc(sectInfo->fRelocCount);
-                               }
-                               if ( sectInfo->fAllZeroFill ) {
-                                       sect->set_flags(S_ZEROFILL);
-                               }
-                               else if ( sectInfo->fAllLazyPointers ) {
-                                       sect->set_flags(S_LAZY_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 ( (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);
-                               }
-                       }
-               }
-               p = &p[macho_segment_command::size + sectionsEmitted*macho_section::content_size];
-               cmd->set_cmdsize(macho_segment_command::size + sectionsEmitted*macho_section::content_size);
-               cmd->set_nsects(sectionsEmitted);
-       }
-       writer.write(0, buffer, size);
-}
-
-
-SymbolTableLoadCommandsAtom::SymbolTableLoadCommandsAtom(Writer& writer)
- : WriterAtom(writer, fgTextSegment)
-{
-       bzero(&fSymbolTable, macho_symtab_command::size);
-       bzero(&fDynamicSymbolTable, macho_dysymtab_command::size);
-       writer.fSymbolTableCommands = this;
-}
-
-uint64_t SymbolTableLoadCommandsAtom::getSize() const
-{
-       return macho_symtab_command::size + macho_dysymtab_command::size;
-}
-
-void SymbolTableLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
-       // build LC_DYSYMTAB command
-       macho_symtab_command   symbolTableCmd;
-       bzero(&symbolTableCmd, macho_symtab_command::size);
-       symbolTableCmd.set_cmd(LC_SYMTAB);
-       symbolTableCmd.set_cmdsize(macho_symtab_command::size);
-       symbolTableCmd.set_nsyms(fWriter.fSymbolTableCount);
-       symbolTableCmd.set_symoff(fWriter.fSymbolTableAtom->getFileOffset());
-       symbolTableCmd.set_stroff(fWriter.fStringsAtom->getFileOffset());
-       symbolTableCmd.set_strsize(fWriter.fStringsAtom->getSize());
-       writer.write(0, &symbolTableCmd, macho_symtab_command::size);
-               
-       // build LC_DYSYMTAB command
-       macho_dysymtab_command dynamicSymbolTableCmd;
-       bzero(&dynamicSymbolTableCmd, macho_dysymtab_command::size);
-       dynamicSymbolTableCmd.set_cmd(LC_DYSYMTAB);
-       dynamicSymbolTableCmd.set_cmdsize(macho_dysymtab_command::size);
-       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);
-       dynamicSymbolTableCmd.set_indirectsymoff(fWriter.fIndirectTableAtom->getFileOffset());
-       dynamicSymbolTableCmd.set_nindirectsyms(fWriter.fIndirectSymbolTable.size());
-       if ( fWriter.fOptions.outputKind() != Options::kObjectFile ) {
-               dynamicSymbolTableCmd.set_extreloff((fWriter.fExternalRelocs.size()==0) ? 0 : fWriter.fExternalRelocationsAtom->getFileOffset());
-               dynamicSymbolTableCmd.set_nextrel(fWriter.fExternalRelocs.size());
-               dynamicSymbolTableCmd.set_locreloff((fWriter.fInternalRelocs.size()==0) ? 0 : fWriter.fLocalRelocationsAtom->getFileOffset());
-               dynamicSymbolTableCmd.set_nlocrel(fWriter.fInternalRelocs.size());
-       }
-       writer.write(macho_symtab_command::size, &dynamicSymbolTableCmd, macho_dysymtab_command::size);
-}
-
-uint64_t DyldLoadCommandsAtom::getSize() const
-{
-       uint32_t len = macho_dylinker_command::name_offset + strlen("/usr/lib/dyld");
-       len = (len+7) & (-8);   // 8-byte align
-       return len;
-}
-
-void DyldLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
-       uint64_t size = this->getSize();
-       uint8_t buffer[size];
-       bzero(buffer, size);
-       macho_dylinker_command* cmd = (macho_dylinker_command*)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[macho_dylinker_command::name_offset], "/usr/lib/dyld");
-       writer.write(0, buffer, size);
-}
-
-
-
-uint64_t DylibLoadCommandsAtom::getSize() const
-{
-       const char* path = fInfo.reader->getInstallPath();
-       if ( fInfo.options.fInstallPathOverride != NULL ) 
-               path = fInfo.options.fInstallPathOverride;
-       uint32_t len = macho_dylib_command::name_offset + strlen(path);
-       len = (len+7) & (-8);   // 8-byte align
-       return len;
-}
-
-void DylibLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
-       uint64_t size = this->getSize();
-       uint8_t buffer[size];
-       bzero(buffer, size);
-       const char* path = fInfo.reader->getInstallPath();
-       if ( fInfo.options.fInstallPathOverride != NULL ) 
-               path = fInfo.options.fInstallPathOverride;
-       macho_dylib_command* cmd = (macho_dylib_command*)buffer;
-       if ( fInfo.options.fWeakImport )
-               cmd->set_cmd(LC_LOAD_WEAK_DYLIB);
-       else
-               cmd->set_cmd(LC_LOAD_DYLIB);
-       cmd->set_cmdsize(this->getSize());
-       cmd->set_timestamp(fInfo.reader->getTimestamp());
-       cmd->set_current_version(fInfo.reader->getCurrentVersion());
-       cmd->set_compatibility_version(fInfo.reader->getCompatibilityVersion());
-       cmd->set_name_offset();
-       strcpy((char*)&buffer[macho_dylib_command::name_offset], path);
-       writer.write(0, buffer, size);
-}
-
-
-
-uint64_t DylibIDLoadCommandsAtom::getSize() const
-{
-       uint32_t len = macho_dylib_command::name_offset + strlen(fWriter.fOptions.installPath());
-       len = (len+7) & (-8);   // 8-byte align
-       return len;
-}
-
-void DylibIDLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
-       struct timeval currentTime = { 0 , 0 };
-       gettimeofday(&currentTime, NULL);
-       time_t timestamp = currentTime.tv_sec;
-       uint64_t size = this->getSize();
-       uint8_t buffer[size];
-       bzero(buffer, size);
-       macho_dylib_command* cmd = (macho_dylib_command*)buffer;
-       cmd->set_cmd(LC_ID_DYLIB);
-       cmd->set_cmdsize(this->getSize());
-       cmd->set_name_offset();
-       cmd->set_timestamp(timestamp);
-       cmd->set_current_version(fWriter.fOptions.currentVersion());
-       cmd->set_compatibility_version(fWriter.fOptions.compatibilityVersion());
-       strcpy((char*)&buffer[macho_dylib_command::name_offset], fWriter.fOptions.installPath());
-       writer.write(0, buffer, size);
-}
-
-
-uint64_t RoutinesLoadCommandsAtom::getSize() const
-{
-       return macho_routines_command::size;
-}
-
-void RoutinesLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
-       uint64_t initAddr = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
-       uint8_t buffer[macho_routines_command::size];
-       bzero(buffer, macho_routines_command::size);
-       macho_routines_command* cmd = (macho_routines_command*)buffer;
-       cmd->set_cmd(macho_routines_command::command);
-       cmd->set_cmdsize(this->getSize());
-       cmd->set_init_address(initAddr);
-       writer.write(0, buffer, macho_routines_command::size);
-}
-
-
-uint64_t SubUmbrellaLoadCommandsAtom::getSize() const
-{
-       uint32_t len = macho_sub_umbrella_command::name_offset + strlen(fName);
-       len = (len+7) & (-8);   // 8-byte align
-       return len;
-}
-
-void SubUmbrellaLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
-       uint64_t size = this->getSize();
-       uint8_t buffer[size];
-       bzero(buffer, size);
-       macho_sub_umbrella_command* cmd = (macho_sub_umbrella_command*)buffer;
-       cmd->set_cmd(LC_SUB_UMBRELLA);
-       cmd->set_cmdsize(this->getSize());
-       cmd->set_name_offset();
-       strcpy((char*)&buffer[macho_sub_umbrella_command::name_offset], fName);
-       writer.write(0, buffer, size);
-}
-
-
-uint64_t SubLibraryLoadCommandsAtom::getSize() const
-{
-       uint32_t len = macho_sub_library_command::name_offset + fNameLength + 1;
-       len = (len+7) & (-8);   // 8-byte align
-       return len;
-}
-
-void SubLibraryLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
-       uint64_t size = this->getSize();
-       uint8_t buffer[size];
-       bzero(buffer, size);
-       macho_sub_library_command* cmd = (macho_sub_library_command*)buffer;
-       cmd->set_cmd(LC_SUB_LIBRARY);
-       cmd->set_cmdsize(this->getSize());
-       cmd->set_name_offset();
-       strncpy((char*)&buffer[macho_sub_library_command::name_offset], fNameStart, fNameLength);
-       buffer[macho_sub_library_command::name_offset+fNameLength] = '\0';
-       writer.write(0, buffer, size);
-}
-
-uint64_t UmbrellaLoadCommandsAtom::getSize() const
-{
-       uint32_t len = macho_sub_framework_command::name_offset + strlen(fName);
-       len = (len+7) & (-8);   // 8-byte align
-       return len;
-}
-
-void UmbrellaLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
-       uint64_t size = this->getSize();
-       uint8_t buffer[size];
-       bzero(buffer, size);
-       macho_sub_framework_command* cmd = (macho_sub_framework_command*)buffer;
-       cmd->set_cmd(LC_SUB_FRAMEWORK);
-       cmd->set_cmdsize(this->getSize());
-       cmd->set_name_offset();
-       strcpy((char*)&buffer[macho_sub_framework_command::name_offset], fName);
-       writer.write(0, buffer, size);
-}
-
-uint64_t ThreadsLoadCommandsAtom::getSize() const
-{
-#if defined(ARCH_PPC)
-               uint32_t stateSize = 40;                // PPC_THREAD_STATE_COUNT;
-#elif defined(ARCH_PPC64)
-               uint32_t stateSize = 76;                // PPC_THREAD_STATE64_COUNT;
-#elif defined(ARCH_I386)
-               uint32_t stateSize = 16;                // i386_THREAD_STATE_COUNT;
-#else
-       #error unknown architecture
-#endif
-       return macho_thread_command::size + stateSize*4;
-}
-
-void ThreadsLoadCommandsAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
-       uint64_t size = this->getSize();
-       uint8_t buffer[size];
-       uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
-       bzero(buffer, size);
-       macho_thread_command* cmd = (macho_thread_command*)buffer;
-       cmd->set_cmd(LC_UNIXTHREAD);
-       cmd->set_cmdsize(size);
-#if defined(ARCH_PPC)
-       cmd->set_flavor(1);                             // PPC_THREAD_STATE
-       cmd->set_count(40);                             // PPC_THREAD_STATE_COUNT;
-       cmd->set_threadState32(0, start);
-       if ( fWriter.fOptions.hasCustomStack() )
-               cmd->set_threadState32(3, fWriter.fOptions.customStackAddr());  // r1
-#elif defined(ARCH_PPC64)
-       cmd->set_flavor(5);                             // PPC_THREAD_STATE64
-       cmd->set_count(76);                             // PPC_THREAD_STATE64_COUNT;
-       cmd->set_threadState64(0, start);
-       if ( fWriter.fOptions.hasCustomStack() )
-               cmd->set_threadState64(6, fWriter.fOptions.customStackAddr());  // r1
-#elif defined(ARCH_I386)
-       cmd->set_flavor(0xFFFFFFFF);    // i386_THREAD_STATE
-       cmd->set_count(16);                             // i386_THREAD_STATE_COUNT;
-       cmd->set_threadState32(0, start);
-       if ( fWriter.fOptions.hasCustomStack() )
-               cmd->set_threadState32(15, fWriter.fOptions.customStackAddr()); // uesp
-#else
-       #error unknown architecture
-#endif
-       writer.write(0, buffer, size);
-}
-
-
-
-uint64_t LoadCommandsPaddingAtom::getSize() const
-{
-       return fSize;
-}
-
-void LoadCommandsPaddingAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
-       uint8_t buffer[fSize];
-       bzero(buffer, fSize);
-       writer.write(0, buffer, fSize);
-}
-
-
-uint64_t LinkEditAtom::getFileOffset() const
-{
-       return ((Writer::SectionInfo*)this->getSection())->fFileOffset + this->getSectionOffset();
-}
-
-
-uint64_t LocalRelocationsLinkEditAtom::getSize() const
-{
-       return fWriter.fInternalRelocs.size() * macho_relocation_info::size;
-}
-
-void LocalRelocationsLinkEditAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
-       writer.write(0, &fWriter.fInternalRelocs[0], this->getSize());
-}
-
-
-
-uint64_t SymbolTableLinkEditAtom::getSize() const
-{
-       return fWriter.fSymbolTableCount * macho_nlist::size;
-}
-
-void SymbolTableLinkEditAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
-       writer.write(0, fWriter.fSymbolTable, this->getSize());
-}
-
-uint64_t ExternalRelocationsLinkEditAtom::getSize() const
-{
-       return fWriter.fExternalRelocs.size() * macho_relocation_info::size;
-}
-
-void ExternalRelocationsLinkEditAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
-       writer.write(0, &fWriter.fExternalRelocs[0], this->getSize());
-}
-
-
-
-uint64_t IndirectTableLinkEditAtom::getSize() const
-{
-       return fWriter.fIndirectSymbolTable.size() * sizeof(uint32_t);
-}
-
-void IndirectTableLinkEditAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
-       uint64_t size = this->getSize();
-       uint8_t buffer[size];
-       bzero(buffer, size);
-       const uint32_t indirectTableSize = fWriter.fIndirectSymbolTable.size();
-       uint32_t* indirectTable = (uint32_t*)buffer;
-       for (uint32_t i=0; i < indirectTableSize; ++i) {
-               Writer::IndirectEntry& entry = fWriter.fIndirectSymbolTable[i];
-               if ( entry.indirectIndex < indirectTableSize ) {
-                       ENDIAN_WRITE32(indirectTable[entry.indirectIndex], entry.symbolIndex);
-               }
-               else {
-                       throwf("malformed indirect table. size=%d, index=%d", indirectTableSize, entry.indirectIndex);
-               }
-       }
-       writer.write(0, buffer, size);
-}
-
-
-
-StringsLinkEditAtom::StringsLinkEditAtom(Writer& writer) 
-       : LinkEditAtom(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';
-}
-
-uint64_t StringsLinkEditAtom::getSize() const
-{
-       return kBufferSize * fFullBuffers.size() + fCurrentBufferUsed;
-}
-
-void StringsLinkEditAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
-       uint64_t offset = 0;
-       for (unsigned int i=0; i < fFullBuffers.size(); ++i) {
-               writer.write(offset, fFullBuffers[i], kBufferSize);
-               offset += kBufferSize;
-       }
-       writer.write(offset, fCurrentBuffer, fCurrentBufferUsed);
-}
-
-int32_t StringsLinkEditAtom::add(const char* name)
-{
-       int lenNeeded = strlen(name)+1;
-       while ( lenNeeded + fCurrentBufferUsed >= kBufferSize ) {
-               // first part of string fits in current buffer
-               int firstLen = kBufferSize - fCurrentBufferUsed;
-               memcpy(&fCurrentBuffer[fCurrentBufferUsed], name, firstLen);
-               // alloc next buffer
-               fFullBuffers.push_back(fCurrentBuffer);
-               fCurrentBuffer = new char[kBufferSize];
-               fCurrentBufferUsed = 0;
-               // advance name to second part
-               name += firstLen;
-               lenNeeded -= firstLen;
-       }
-       //fprintf(stderr, "StringsLinkEditAtom::add(): lenNeeded=%d, fCurrentBuffer=%d, fCurrentBufferUsed=%d\n", lenNeeded, fCurrentBuffer, fCurrentBufferUsed);
-       // string all fits in current buffer
-       strcpy(&fCurrentBuffer[fCurrentBufferUsed], name);
-       int32_t offset = kBufferSize * fFullBuffers.size() + fCurrentBufferUsed;
-       fCurrentBufferUsed += lenNeeded;
-       return offset;
-}
-
-// returns the index of an empty string
-int32_t StringsLinkEditAtom::emptyString()
-{
-        return 1;
-}
-
-#if defined(ARCH_PPC) || defined(ARCH_PPC64) 
-BranchIslandAtom::BranchIslandAtom(Writer& writer, const char* name, int islandRegion, ObjectFile::Atom& target, uint32_t targetOffset) 
- : WriterAtom(writer, fgTextSegment), fTarget(target), fTargetOffset(targetOffset)
-{
-       char* buf = new char[strlen(name)+32];
-       if ( targetOffset == 0 ) {
-               if ( islandRegion == 0 )
-                       sprintf(buf, "%s$island", name);
-               else
-                       sprintf(buf, "%s$island_%d", name, islandRegion);
-       }
-       else {
-               sprintf(buf, "%s_plus_%d$island_%d", name, targetOffset, islandRegion);
-       }
-       fName = buf;
-}
-
-
-void BranchIslandAtom::writeContent(bool finalLinkedImage, ObjectFile::ContentWriter& writer) const
-{
-       int64_t displacement = fTarget.getAddress() + fTargetOffset - this->getAddress();
-       uint8_t instruction[4];
-       int32_t branchInstruction = 0x48000000 | ((uint32_t)displacement & 0x03FFFFFC);
-       OSWriteBigInt32(&instruction, 0, branchInstruction);                    
-       writer.write(0, &instruction, 4);
-}
-
-
-#endif
-
-
-};
-
-
-
diff --git a/src/debugline.c b/src/debugline.c
new file mode 100644 (file)
index 0000000..ff0e1d9
--- /dev/null
@@ -0,0 +1,546 @@
+/*
+ * 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 KLD
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include "dwarf2.h"
+#include "debugline.h"
+
+struct line_reader_data 
+{
+  bool little_endian;
+  
+  /* From the line number information header.  */
+  uint8_t minimum_instruction_length;
+  int8_t line_base;
+  uint8_t line_range;
+  uint8_t opcode_base;
+  const uint8_t * standard_opcode_lengths;
+  size_t numdir;
+  const uint8_t * * dirnames;
+  size_t numfile_orig;
+  size_t numfile;  /* As updated during execution of the table.  */
+  const uint8_t * * filenames;
+
+  /* Current position in the line table.  */
+  const uint8_t * cpos;
+  /* End of this part of the line table.  */
+  const uint8_t * end;
+  /* Start of the line table.  */
+  const uint8_t * init;
+
+  struct line_info cur;
+};
+
+/* Read in a word of fixed size, which may be unaligned, in the
+   appropriate endianness.  */
+#define read_16(p) (lnd->little_endian         \
+                   ? ((p)[1] << 8 | (p)[0])    \
+                   : ((p)[0] << 8 | (p)[1]))
+#define read_32(p) (lnd->little_endian                                     \
+                   ? ((p)[3] << 24 | (p)[2] << 16 | (p)[1] << 8 | (p)[0])  \
+                   : ((p)[0] << 24 | (p)[1] << 16 | (p)[2] << 8 | (p)[3]))
+#define read_64(p) (lnd->little_endian                                     \
+                   ? ((uint64_t) (p)[7] << 56 | (uint64_t) (p)[6] << 48    \
+                      | (uint64_t) (p)[5] << 40 | (uint64_t) (p)[4] << 32  \
+                      | (uint64_t) (p)[3] << 24 | (uint64_t) (p)[2] << 16u \
+                      | (uint64_t) (p)[1] << 8 | (uint64_t) (p)[0])        \
+                   : ((uint64_t) (p)[0] << 56 | (uint64_t) (p)[1] << 48    \
+                      | (uint64_t) (p)[2] << 40 | (uint64_t) (p)[3] << 32  \
+                      | (uint64_t) (p)[4] << 24 | (uint64_t) (p)[5] << 16u \
+                      | (uint64_t) (p)[6] << 8 | (uint64_t) (p)[7]))
+
+/* Skip over a LEB128 value (signed or unsigned).  */
+static void
+skip_leb128 (struct line_reader_data * leb)
+{
+  while (leb->cpos != leb->end && *leb->cpos >= 0x80)
+    leb->cpos++;
+  if (leb->cpos != leb->end)
+    leb->cpos++;
+}
+
+/* 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 (struct line_reader_data * leb)
+{
+  uint64_t result = 0;
+  int bit = 0;
+  
+  do  {
+    uint64_t b;
+    
+    if (leb->cpos == leb->end)
+      return (uint64_t) -1;
+  
+    b = *leb->cpos & 0x7f;
+    
+    if (bit >= 64 || b << bit >> bit != b)
+      result = (uint64_t) -1;
+    else
+      result |= b << bit, bit += 7;
+  } while (*leb->cpos++ >= 0x80);
+  return result;
+}
+
+
+/* Read a SLEB128 into a 64-bit word.  Return 0 on overflow or error
+   (which is not very helpful).  On overflow, skip past the rest of
+   the SLEB128.  For negative numbers, this actually overflows when
+   under -2^62, but since this is used for line numbers that ought to
+   be OK...  */
+static int64_t
+read_sleb128 (struct line_reader_data * leb)
+{
+  const uint8_t * start_pos = leb->cpos;
+  uint64_t v = read_uleb128 (leb);
+  uint64_t signbit;
+  
+  if (v >= 1ull << 63)
+    return 0;
+  if (leb->cpos - start_pos > 9)
+    return v;
+
+  signbit = 1ull << ((leb->cpos - start_pos) * 7 - 1);
+
+  return v | -(v & signbit);
+}
+
+/* Free a line_reader_data structure.  */
+void
+line_free (struct line_reader_data * lnd)
+{
+  if (! lnd)
+    return;
+  if (lnd->dirnames)
+    free (lnd->dirnames);
+  if (lnd->filenames)
+    free (lnd->filenames);
+  free (lnd);
+}
+
+/* Return the pathname of the file in S, or NULL on error. 
+   The result will have been allocated with malloc.  */
+
+char *
+line_file (struct line_reader_data *lnd, uint64_t n)
+{
+  const uint8_t * prev_pos = lnd->cpos;
+  size_t filelen, dirlen;
+  uint64_t dir;
+  char * result;
+
+  /* I'm not sure if this is actually an error.  */
+  if (n == 0
+      || n > lnd->numfile)
+    return NULL;
+
+  filelen = strlen ((const char *)lnd->filenames[n - 1]);
+  lnd->cpos = lnd->filenames[n - 1] + filelen + 1;
+  dir = read_uleb128 (lnd);
+  lnd->cpos = prev_pos;
+  if (dir == 0
+      || lnd->filenames[n - 1][0] == '/')
+    return strdup ((const char *)lnd->filenames[n - 1]);
+  else if (dir > lnd->numdir)
+    return NULL;
+
+  dirlen = strlen ((const char *) lnd->dirnames[dir - 1]);
+  result = malloc (dirlen + filelen + 2);
+  memcpy (result, lnd->dirnames[dir - 1], dirlen);
+  result[dirlen] = '/';
+  memcpy (result + dirlen + 1, lnd->filenames[n - 1], filelen);
+  result[dirlen + 1 + filelen] = '\0';
+  return result;
+}
+
+/* Initialize a state S.  Return FALSE on error.  */
+
+static void
+init_state (struct line_info *s)
+{
+  s->file = 1;
+  s->line = 1;
+  s->col = 0;
+  s->pc = 0;
+  s->end_of_sequence = false;
+}
+
+/* Read a debug_line section.  */
+
+struct line_reader_data *
+line_open (const uint8_t * debug_line, size_t debug_line_size,
+          int little_endian)
+{
+  struct line_reader_data * lnd = NULL;
+  bool dwarf_size_64;
+
+  uint64_t lnd_length, header_length;
+  const uint8_t * table_start;
+
+  if (debug_line_size < 12)
+    return NULL;
+  
+  lnd = malloc (sizeof (struct line_reader_data));
+  if (! lnd)
+    goto error;
+  
+  lnd->little_endian = little_endian;
+  lnd->cpos = debug_line;
+
+  lnd_length = read_32 (lnd->cpos);
+  lnd->cpos += 4;
+  if (lnd_length == 0xffffffff)
+    {
+      lnd_length = read_64 (lnd->cpos);
+      lnd->cpos += 8;
+      dwarf_size_64 = true;
+    }
+  else if (lnd_length > 0xfffffff0)
+    /* Not a format we understand.  */
+    goto error;
+  else
+    dwarf_size_64 = false;
+
+  if (debug_line_size < lnd_length + (dwarf_size_64 ? 12 : 4)
+      || lnd_length < (dwarf_size_64 ? 15 : 11))
+    /* Too small.  */
+    goto error;
+  
+  if (read_16 (lnd->cpos) != 2)
+    /* Unknown line number format.  */
+    goto error;
+  lnd->cpos += 2;
+
+  header_length = dwarf_size_64 ? (uint64_t)read_64(lnd->cpos) : (uint64_t)read_32(lnd->cpos);
+  lnd->cpos += dwarf_size_64 ? 8 : 4;
+  if (lnd_length < header_length + (lnd->cpos - debug_line)
+      || header_length < 7)
+    goto error;
+
+  lnd->minimum_instruction_length = lnd->cpos[0];
+  /* Ignore default_is_stmt.  */
+  lnd->line_base = lnd->cpos[2];
+  lnd->line_range = lnd->cpos[3];
+  lnd->opcode_base = lnd->cpos[4];
+
+  if (lnd->opcode_base == 0)
+    /* Every valid line number program must use at least opcode 0
+       for DW_LNE_end_sequence.  */
+    goto error;
+
+  lnd->standard_opcode_lengths = lnd->cpos + 5;
+  if (header_length < (uint64_t)(5 + (lnd->opcode_base - 1)))
+    /* Header not long enough.  */
+    goto error;
+  lnd->cpos += 5 + lnd->opcode_base - 1;
+  lnd->end = debug_line + header_length + (dwarf_size_64 ? 22 : 10);
+  
+  /* Make table of offsets to directory names.  */
+  table_start = lnd->cpos;
+  lnd->numdir = 0;
+  while (lnd->cpos != lnd->end && *lnd->cpos)
+    {
+      lnd->cpos = memchr (lnd->cpos, 0, lnd->end - lnd->cpos);
+      if (! lnd->cpos)
+       goto error;
+      lnd->cpos++;
+      lnd->numdir++;
+    }
+  if (lnd->cpos == lnd->end)
+    goto error;
+  lnd->dirnames = malloc (lnd->numdir * sizeof (const uint8_t *));
+  if (! lnd->dirnames)
+    goto error;
+  lnd->numdir = 0;
+  lnd->cpos = table_start;
+  while (*lnd->cpos)
+    {
+      lnd->dirnames[lnd->numdir++] = lnd->cpos;
+      lnd->cpos = memchr (lnd->cpos, 0, lnd->end - lnd->cpos) + 1;
+    }
+  lnd->cpos++;
+  
+  /* Make table of offsets to file entries.  */
+  table_start = lnd->cpos;
+  lnd->numfile = 0;
+  while (lnd->cpos != lnd->end && *lnd->cpos)
+    {
+      lnd->cpos = memchr (lnd->cpos, 0, lnd->end - lnd->cpos);
+      if (! lnd->cpos)
+       goto error;
+      lnd->cpos++;
+      skip_leb128 (lnd);
+      skip_leb128 (lnd);
+      skip_leb128 (lnd);
+      lnd->numfile++;
+    }
+  if (lnd->cpos == lnd->end)
+    goto error;
+  lnd->filenames = malloc (lnd->numfile * sizeof (const uint8_t *));
+  if (! lnd->filenames)
+    goto error;
+  lnd->numfile = 0;
+  lnd->cpos = table_start;
+  while (*lnd->cpos)
+    {
+      lnd->filenames[lnd->numfile++] = lnd->cpos;
+      lnd->cpos = memchr (lnd->cpos, 0, lnd->end - lnd->cpos) + 1;
+      skip_leb128 (lnd);
+      skip_leb128 (lnd);
+      skip_leb128 (lnd);
+    }
+  lnd->cpos++;
+  
+  lnd->numfile_orig = lnd->numfile;
+  lnd->cpos = lnd->init = lnd->end;
+  lnd->end = debug_line + lnd_length + (dwarf_size_64 ? 12 : 4);
+
+  init_state (&lnd->cur);
+
+  return lnd;
+  
+ error:
+  line_free (lnd);
+  return NULL;
+}
+
+/* Reset back to the beginning.  */
+void
+line_reset (struct line_reader_data * lnd)
+{
+  lnd->cpos = lnd->init;
+  lnd->numfile = lnd->numfile_orig;
+  init_state (&lnd->cur);
+}
+
+/* Is there no more line data available?  */
+int
+line_at_eof (struct line_reader_data * lnd)
+{
+  return lnd->cpos == lnd->end;
+}
+
+static bool
+next_state (struct line_reader_data *lnd)
+{
+  if (lnd->cur.end_of_sequence)
+    init_state (&lnd->cur);
+
+  for (;;)
+    {
+      uint8_t op;
+      uint64_t tmp;
+      
+      if (lnd->cpos == lnd->end)
+       return false;
+      op = *lnd->cpos++;
+      if (op >= lnd->opcode_base)
+       {
+         op -= lnd->opcode_base;
+         
+         lnd->cur.line += op % lnd->line_range + lnd->line_base;
+         lnd->cur.pc += (op / lnd->line_range 
+                         * lnd->minimum_instruction_length);
+         return true;
+       }
+      else switch (op)
+       {
+       case DW_LNS_extended_op:
+         {
+           uint64_t sz = read_uleb128 (lnd);
+           const uint8_t * op = lnd->cpos;
+           
+           if ((uint64_t)(lnd->end - op) < sz || sz == 0)
+             return false;
+           lnd->cpos += sz;
+           switch (*op++)
+             {
+             case DW_LNE_end_sequence:
+               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);
+               else
+                 return false;
+               break;
+               
+             case DW_LNE_define_file:
+               {
+                 const uint8_t * * filenames;
+                 filenames = realloc 
+                   (lnd->filenames, 
+                    (lnd->numfile + 1) * sizeof (const uint8_t *));
+                 if (! filenames)
+                   return false;
+                 /* Check for zero-termination.  */
+                 if (! memchr (op, 0, lnd->cpos - op))
+                   return false;
+                 filenames[lnd->numfile++] = op;
+                 lnd->filenames = filenames;
+
+                 /* There's other data here, like file sizes and modification
+                    times, but we don't need to read it so skip it.  */
+               }
+               break;
+               
+             default:
+               /* Don't understand it, so skip it.  */
+               break;
+             }
+           break;
+         }
+         
+       case DW_LNS_copy:
+       //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;
+         break;
+       case DW_LNS_advance_line:
+       //fprintf(stderr, "DW_LNS_advance_line\n");
+         lnd->cur.line += read_sleb128 (lnd);
+         break;
+       case DW_LNS_set_file:
+       //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");
+         lnd->cur.col = read_uleb128 (lnd);
+         break;
+       case DW_LNS_const_add_pc:
+       //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 (lnd->end - lnd->cpos < 2)
+           return false;
+         lnd->cur.pc += read_16 (lnd->cpos);
+         lnd->cpos += 2;
+         break;
+       default:
+         {
+           /* Don't know what it is, so skip it.  */
+           int i;
+           for (i = 0; i < lnd->standard_opcode_lengths[op - 1]; i++)
+             skip_leb128 (lnd);
+           break;
+         }
+       }
+    }
+}
+
+
+/* Set RESULT to the next 'interesting' line state, as indicated
+   by STOP, or return FALSE on error.  The final (end-of-sequence)
+   line state is always considered interesting.  */
+int
+line_next (struct line_reader_data * lnd,
+          struct line_info * result,
+          enum line_stop_constants stop)
+{
+  for (;;)
+    {
+      struct line_info prev = lnd->cur;
+
+      if (! next_state (lnd))
+       return false;
+
+      if (lnd->cur.end_of_sequence)
+       break;
+      if (stop == line_stop_always)
+       break;
+      if ((stop & line_stop_pc) && lnd->cur.pc != prev.pc)
+       break;
+      if ((stop & line_stop_pos_mask) && lnd->cur.file != prev.file)
+       break;
+      if ((stop & line_stop_pos_mask) >= line_stop_line
+         && lnd->cur.line != prev.line)
+       break;
+      if ((stop & line_stop_pos_mask) >= line_stop_col
+         && lnd->cur.col != prev.col)
+       break;
+    }
+  *result = lnd->cur;
+  return true;
+}
+
+/* Find the region (START->pc through END->pc) in the debug_line
+   information which contains PC.  This routine starts searching at
+   the current position (which is returned as END), and will go all
+   the way around the debug_line information.  It will return false if
+   an error occurs or if there is no matching region; these may be
+   distinguished by looking at START->end_of_sequence, which will be
+   false on error and true if there was no matching region.
+   You could write this routine using line_next, but this version
+   will be slightly more efficient, and of course more convenient.  */
+
+int
+line_find_addr (struct line_reader_data * lnd,
+               struct line_info * start,
+               struct line_info * end,
+               uint64_t pc)
+{
+  const uint8_t * startpos;
+  struct line_info prev;
+
+  if (lnd->cur.end_of_sequence && lnd->cpos == lnd->end)
+    line_reset (lnd);
+
+  startpos = lnd->cpos;
+
+  do {
+    prev = lnd->cur;
+    if (! next_state (lnd))
+      {
+       start->end_of_sequence = false;
+       return false;
+      }
+    if (lnd->cur.end_of_sequence && lnd->cpos == lnd->end)
+      line_reset (lnd);
+    if (lnd->cpos == startpos)
+      {
+       start->end_of_sequence = true;
+       return false;
+      }
+  } while (lnd->cur.pc <= pc || prev.pc > pc || prev.end_of_sequence);
+  *start = prev;
+  *end = lnd->cur;
+  return true;
+}
+#endif /* ! KLD */
+
diff --git a/src/debugline.h b/src/debugline.h
new file mode 100644 (file)
index 0000000..51d585e
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * 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 <stdint.h>
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Information about a line.
+   DIRECTORY is to be ignored if FILENAME is absolute.  
+   PC will be relative to the file the debug_line section is in.  */
+struct line_info
+{
+  uint64_t file;
+  int64_t line;
+  uint64_t col;
+  uint64_t pc;
+  int end_of_sequence;
+};
+
+/* Opaque status structure for the line readers.  */
+struct line_reader_data;
+
+/* Create a line_reader_data, given address and size of the debug_line section.
+   SIZE may be (size_t)-1 if unknown, although this suppresses checking
+   for an incorrectly large size in the debug_line section.
+   LITTLE_ENDIAN is set if the debug_line section is for a little-endian
+   machine.
+   Returns NULL on error.  */
+struct line_reader_data * line_open (const uint8_t * debug_line,
+                                    size_t debug_line_size,
+                                    int little_endian);
+
+/* The STOP parameter to line_next is one of line_stop_{file,line,col},
+   perhaps ORed with line_stop_pc; or line_stop_atend, or line_stop_always.  */
+enum line_stop_constants {
+  line_stop_atend = 0, /* Stop only at the end of a sequence.  */
+  line_stop_file = 1,  /* Stop if DIRECTORY or FILENAME change.  */
+  line_stop_line = 2,  /* Stop if LINE, DIRECTORY, or FILENAME change.  */
+  line_stop_col = 3,   /* Stop if COL, LINE, DIRECTORY, or FILENAME change.  */
+  line_stop_pos_mask = 3,
+  line_stop_pc = 4,    /* Stop if PC changes.  */
+  line_stop_always = 8 /* Stop always.  */
+};
+
+/* Either return FALSE on an error, in which case the line_reader_data
+   may be invalid and should be passed immediately to line_free; or
+   fill RESULT with the first 'interesting' line, as determined by STOP.
+   The last line data in a sequence is always considered 'interesting'.  */
+int line_next (struct line_reader_data * lnd,
+               struct line_info * result,
+               enum line_stop_constants stop);
+
+/* Find the region (START->pc through END->pc) in the debug_line
+   information which contains PC.  This routine starts searching at
+   the current position (which is returned as END), and will go all
+   the way around the debug_line information.  It will return false if
+   an error occurs or if there is no matching region; these may be
+   distinguished by looking at START->end_of_sequence, which will be
+   false on error and true if there was no matching region.
+   You could write this routine using line_next, but this version
+   will be slightly more efficient, and of course more convenient.  */
+
+int line_find_addr (struct line_reader_data * lnd,
+                    struct line_info * start,
+                    struct line_info * end,
+                    uint64_t pc);
+
+/* Return TRUE if there is more line data to be fetched.
+   If line_next has not been called or it has been called but did not
+   set END_OF_SEQUENCE, you can assume there is more line data,
+   but it's safe to call this routine anyway.  */
+int line_at_eof (struct line_reader_data * lnd);
+
+/* Return the pathname of the file in S, or NULL on error. 
+   The result will have been allocated with malloc.  */
+char * line_file (struct line_reader_data *lnd, uint64_t file);
+
+/* Reset the line_reader_data: go back to the beginning.  */
+void line_reset (struct line_reader_data * lnd);
+
+/* Free a line_reader_data structure.  */
+void line_free (struct line_reader_data * lnd);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/src/dwarf2.h b/src/dwarf2.h
new file mode 100644 (file)
index 0000000..530b465
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * 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@
+ */
+/* These constants were taken from version 3 of the DWARF standard,
+   which is Copyright (c) 2005 Free Standards Group, and
+   Copyright (c) 1992, 1993 UNIX International, Inc.  */
+
+/* This is not a complete list.  */
+enum {
+  DW_TAG_compile_unit = 17,
+  DW_TAG_partial_unit = 60
+};
+
+/* This is not a complete list.  */
+enum {
+  DW_AT_sibling = 1,
+  DW_AT_name = 3,
+  DW_AT_stmt_list = 16,
+  DW_AT_comp_dir = 27
+};
+
+enum {
+  DW_FORM_addr = 1,
+  DW_FORM_block2 = 3,
+  DW_FORM_block4,
+  DW_FORM_data2,
+  DW_FORM_data4,
+  DW_FORM_data8,
+  DW_FORM_string,
+  DW_FORM_block,
+  DW_FORM_block1,
+  DW_FORM_data1,
+  DW_FORM_flag,
+  DW_FORM_sdata,
+  DW_FORM_strp,
+  DW_FORM_udata,
+  DW_FORM_ref_addr,
+  DW_FORM_ref1,
+  DW_FORM_ref2,
+  DW_FORM_ref4,
+  DW_FORM_ref8,
+  DW_FORM_ref_udata,
+  DW_FORM_indirect /* 22 */
+};
+
+enum {
+  DW_LNS_extended_op = 0,
+  DW_LNS_copy,
+  DW_LNS_advance_pc,
+  DW_LNS_advance_line,
+  DW_LNS_set_file,
+  DW_LNS_set_column,
+  DW_LNS_negate_stmt,
+  DW_LNS_set_basic_block,
+  DW_LNS_const_add_pc,
+  DW_LNS_fixed_advance_pc,
+  DW_LNS_set_prologue_end,
+  DW_LNS_set_epilogue_begin,
+  DW_LNS_set_isa
+};
+
+enum {
+  DW_LNE_end_sequence = 1,
+  DW_LNE_set_address,
+  DW_LNE_define_file
+};
index 3b6805946e9c1fc9061e809bb97369965179de4c..e98df10b0c335dd3f1cad8fcbafbb85d8bb543be 100644 (file)
@@ -1,16 +1,16 @@
-/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * 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,
  * 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 <mach-o/loader.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 <mach-o/fat.h>
 
+
 #include <string>
 #include <set>
 #include <string>
 #include "Options.h"
 
 #include "ObjectFile.h"
-#include "ObjectFileMachO-all.h"
 
-#include "ExecutableFile.h"
-#include "ExecutableFileMachO-all.h"
+#include "MachOReaderRelocatable.hpp"
+#include "MachOReaderArchive.hpp"
+#include "MachOReaderDylib.hpp"
+#include "MachOWriterExecutable.hpp"
 
 #include "SectCreate.h"
 
 static void dumpAtom(ObjectFile::Atom* atom)
 {
        //printf("atom:    %p\n", atom);
-       
+
        // name
        printf("name:    %s\n",  atom->getDisplayName());
-       
+
        // scope
        switch ( atom->getScope() ) {
                case ObjectFile::Atom::scopeTranslationUnit:
@@ -70,29 +77,42 @@ static void dumpAtom(ObjectFile::Atom* atom)
                default:
                        printf("scope:   unknown\n");
        }
-       
+
+       // kind
+       switch ( atom->getDefinitinonKind() ) {
+               case ObjectFile::Atom::kRegularDefinition:
+                       printf("kind:     regular\n");
+                       break;
+               case ObjectFile::Atom::kWeakDefinition:
+                       printf("kind:     weak\n");
+                       break;
+               case ObjectFile::Atom::kTentativeDefinition:
+                       printf("kind:     tentative\n");
+                       break;
+               case ObjectFile::Atom::kExternalDefinition:
+                       printf("kind:     import\n");
+                       break;
+               case ObjectFile::Atom::kExternalWeakDefinition:
+                       printf("kind:     weak import\n");
+                       break;
+               default:
+                       printf("scope:   unknown\n");
+       }
+
        // segment and section
        printf("section: %s,%s\n", atom->getSegment().getName(), atom->getSectionName());
 
        // attributes
        printf("attrs:   ");
-       if ( atom->isTentativekDefinition() )
-               printf("tentative ");
-       else if ( atom->isWeakDefinition() )
-               printf("weak ");
-       if ( atom->isCoalesableByName() )
-               printf("coalesce-by-name ");
-       if ( atom->isCoalesableByValue() )
-               printf("coalesce-by-value ");
        if ( atom->dontDeadStrip() )
                printf("dont-dead-strip ");
        if ( atom->isZeroFill() )
                printf("zero-fill ");
        printf("\n");
-       
+
        // size
        printf("size:    0x%012llX\n", atom->getSize());
-       
+
        // content
        uint8_t content[atom->getSize()];
        atom->copyRawContent(content);
@@ -105,7 +125,7 @@ static void dumpAtom(ObjectFile::Atom* atom)
                        printf("%02X ", content[i]);
        }
        printf("\n");
-       
+
        // references
        std::vector<ObjectFile::Reference*>&  references = atom->getReferences();
        const int refCount = references.size();
@@ -114,9 +134,9 @@ static void dumpAtom(ObjectFile::Atom* atom)
                ObjectFile::Reference* ref = references[i];
                printf("   %s\n", ref->getDescription());
        }
-       
+
        // attributes
-       
+
 }
 
 #endif
@@ -169,13 +189,6 @@ Section::Section(const char* sectionName, const char* segmentName, bool zeroFill
 
 Section* Section::find(const char* sectionName, const char* segmentName, bool zeroFill)
 {
-#if 0
-       std::pair<NameToSection::iterator, NameToSection::iterator> range = fgMapping.equal_range(sectionName);
-       for (NameToSection::iterator it=range.first; it != range.second; it++) {
-               if ( strcmp(it->second->fSegmentName, segmentName) == 0 )
-                       return it->second;
-       }
-#endif
        NameToSection::iterator pos = fgMapping.find(sectionName);
        if ( pos != fgMapping.end() ) {
                if ( strcmp(pos->second->fSegmentName, segmentName) == 0 )
@@ -186,12 +199,18 @@ Section* Section::find(const char* sectionName, const char* segmentName, bool ze
                                return *it;
                }
        }
-       
+
        // does not exist, so make a new one
        Section* sect = new Section(sectionName, segmentName, zeroFill);
        sect->fIndex = fgMapping.size();
        fgMapping[sectionName] = sect;
        fgSections.push_back(sect);
+
+       if ( (strcmp(sectionName, "__text") == 0) && (strcmp(segmentName, "__TEXT") == 0) ) {
+               // special case __textcoal_nt to be right after __text
+               find("__textcoal_nt", "__TEXT", false);
+       }
+
        return sect;
 }
 
@@ -207,7 +226,7 @@ int Section::Sorter::segmentOrdinal(const char* segName)
                return 4;
        if ( strcmp(segName, "__LINKEDIT") == 0 )
                return INT_MAX; // linkedit segment should always sort last
-       else 
+       else
                return 5;
 }
 
@@ -248,10 +267,10 @@ void Section::assignIndexes()
 
        // sort it
        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++) 
+       for (std::vector<Section*>::iterator it=fgSections.begin(); it != fgSections.end(); it++)
                (*it)->fIndex = newOrder++;
 
        //printf("sorted:\n");
@@ -269,8 +288,8 @@ public:
        void                            addInputFile(ObjectFile::Reader* reader);
        void                            setOutputFile(ExecutableFile::Writer* writer);
        void                            link();
-       
-       
+
+
 private:
        ObjectFile::Reader*     createReader(const Options::FileInfo&);
        void                            addAtom(ObjectFile::Atom& atom);
@@ -282,17 +301,35 @@ private:
        void                            deadStrip();
        void                            sortAtoms();
        void                            tweakLayout();
+       void                            writeDotOutput();
+       static bool                     minimizeStab(ObjectFile::Reader::Stab& stab);
+       static const char*      truncateStabString(const char* str);
+       void                            collectStabs();
        void                            writeOutput();
-       
+       ObjectFile::Atom*       entryPoint();
+       ObjectFile::Atom*       dyldHelper();
+       const char*                     assureFullPath(const char* path);
+       void                            markLive(ObjectFile::Atom* atom, std::set<ObjectFile::Atom*>& liveAtoms);
+       void                            collectStabs(ObjectFile::Reader* reader);
+       void                            synthesizeStabs(ObjectFile::Reader* reader);
+       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                            resolve(ObjectFile::Reference* reference);
        void                            resolveFrom(ObjectFile::Reference* reference);
        void                            addJustInTimeAtoms(const char* name);
-       
-       void                            addDylib(ObjectFile::Reader* reader, const Options::FileInfo& info);
+
+       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                            addIndirectLibraries(ObjectFile::Reader* reader);
        bool                            haveIndirectLibrary(const char* path, ObjectFile::Reader* reader);
        bool                            haveDirectLibrary(const char* path);
-       
+
+       void                            logTraceInfo(const char* format, ...);
        class SymbolTable
        {
        public:
@@ -303,27 +340,29 @@ private:
                unsigned int            getRequireCount() { return fRequireCount; }
                void                            getNeededNames(bool andWeakDefintions, std::vector<const char*>& undefines);
        private:
-               typedef std::map<const char*, ObjectFile::Atom*, CStringComparor> Mapper;
+               typedef __gnu_cxx::hash_map<const char*, ObjectFile::Atom*, __gnu_cxx::hash<const char*>, CStringEquals> Mapper;
                Linker&                         fOwner;
                Mapper                          fTable;
                unsigned int            fRequireCount;
        };
-       
+
        struct AtomSorter
        {
                bool operator()(ObjectFile::Atom* left, ObjectFile::Atom* right);
        };
-       
+
        typedef std::map<const char*, uint32_t, CStringComparor> SectionOrder;
-       
+
        struct IndirectLibrary {
                const char*                                                     path;
                uint64_t                                                        fileLen;
                ObjectFile::Reader*                                     reader;
                std::set<ObjectFile::Reader*>           parents;
-               ObjectFile::Reader*                                     reExportParent;
+               ObjectFile::Reader*                                     reExportedViaDirectLibrary;
        };
-       
+
+       ObjectFile::Reader* findDirectLibraryWhichReExports(struct IndirectLibrary& indirectLib);
+
        Options                                                                                         fOptions;
        SymbolTable                                                                                     fGlobalSymbolTable;
        unsigned int                                                                            fWeakSymbolsAddedCount;
@@ -331,22 +370,96 @@ private:
        ExecutableFile::Writer*                                                         fOutputFile;
        std::vector<ExecutableFile::DyLibUsed>                          fDynamicLibraries;
        std::list<IndirectLibrary>                                                      fIndirectDynamicLibraries;
+       std::vector<class ObjectFile::Reader*>                          fReadersThatHaveSuppliedAtoms;
        std::vector<class ObjectFile::Atom*>                            fAllAtoms;
        std::set<class ObjectFile::Atom*>                                       fDeadAtoms;
+       std::vector<class ObjectFile::Reader::Stab>                     fStabs;
+       bool                                                                                            fCreateUUID;
        SectionOrder                                                                            fSectionOrder;
        unsigned int                                                                            fNextSortOrder;
+       unsigned int                                                                            fNextObjectFileOrder;
+       cpu_type_t                                                                                      fArchitecture;
        bool                                                                                            fDirectLibrariesComplete;
+       uint64_t                                                                                        fOutputFileSize;
+       uint64_t                                                                                        fStartTime;
+       uint64_t                                                                                        fStartCreateReadersTime;
+       uint64_t                                                                                        fStartCreateWriterTime;
+       uint64_t                                                                                        fStartBuildAtomsTime;
+       uint64_t                                                                                        fStartLoadUndefinesTime;
+       uint64_t                                                                                        fStartResolveTime;
+       uint64_t                                                                                        fStartSortTime;
+       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;
 };
 
 
-
 Linker::Linker(int argc, const char* argv[])
- : fOptions(argc, argv), fGlobalSymbolTable(*this), fOutputFile(NULL), fNextSortOrder(1), fDirectLibrariesComplete(false)
+       : fOptions(argc, argv), fGlobalSymbolTable(*this), fOutputFile(NULL), fCreateUUID(false), fNextSortOrder(1),
+         fNextObjectFileOrder(1), fArchitecture(0), fDirectLibrariesComplete(false), fOutputFileSize(0), fTotalObjectSize(0),
+         fTotalArchiveSize(0),  fTotalObjectLoaded(0), fTotalArchivesLoaded(0), fTotalDylibsLoaded(0)
 {
+       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();
+       }
 }
 
+cpu_type_t Linker::inferArchitecture()
+{
+       // 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) ) {
+                                       fprintf(stderr, "ld64 warning: -arch not used, infering -arch ppc based on %s\n", it->path);
+                                       return CPU_TYPE_POWERPC;
+                               }
+                               else if ( mach_o::relocatable::Reader<ppc64>::validFile(buffer) ) {
+                                       fprintf(stderr, "ld64 warning: -arch not used, infering -arch ppc64 based on %s\n", it->path);
+                                       return CPU_TYPE_POWERPC64;
+                               }
+                               else if ( mach_o::relocatable::Reader<x86>::validFile(buffer) ) {
+                                       fprintf(stderr, "ld64 warning: -arch not used, infering -arch i386 based on %s\n", it->path);
+                                       return CPU_TYPE_I386;
+                               }
+                       }
+               }
+       }
+       
+       // no thin .o files found, so default to same architecture this was built as
+       fprintf(stderr, "ld64 warning: -arch not specified\n");
+#if __ppc__
+       return CPU_TYPE_POWERPC;
+#elif __i386__
+       return CPU_TYPE_I386;
+#elif __ppc64__
+       return CPU_TYPE_POWERPC64;
+#else
+       #error unknown default architecture
+#endif
+}
+
+
 void Linker::addInputFile(ObjectFile::Reader* reader)
 {
+       reader->setSortOrder(fNextObjectFileOrder++);
        fInputFiles.push_back(reader);
 }
 
@@ -356,21 +469,106 @@ void Linker::setOutputFile(ExecutableFile::Writer* writer)
 }
 
 void Linker::link()
-{      
+{
        this->buildAtomList();
        this->loadUndefines();
        this->resolveReferences();
        this->deadStrip();
        this->sortAtoms();
        this->tweakLayout();
+       this->writeDotOutput();
+       this->collectStabs();
        this->writeOutput();
+       this->printStatistics();
+
+       if ( fOptions.pauseAtEnd() )
+               sleep(10);
+}
+
+void Linker::printTime(const char* msg, uint64_t partTime, uint64_t totalTime)
+{
+       static uint64_t sUnitsPerSecond = 0;
+       if ( sUnitsPerSecond == 0 ) {
+               struct mach_timebase_info timeBaseInfo;
+               if ( mach_timebase_info(&timeBaseInfo) == KERN_SUCCESS ) {
+                       sUnitsPerSecond = 1000000000LL * 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);
+       }
+}
+
+char* Linker::commatize(uint64_t in, char* out)
+{
+       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;
+}
+
+void Linker::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,
+                                                       (host_info_t)&info, &count);
+       if (error != KERN_SUCCESS) {
+               bzero(&info, sizeof(vm_statistics_data_t));
+       }
+}
+
+void Linker::printStatistics()
+{
+       fEndTime = mach_absolute_time();
+       if ( fOptions.printStatistics() ) {
+               vm_statistics_data_t endVMInfo;
+               getVMInfo(endVMInfo);
+
+               uint64_t totalTime = fEndTime - fStartTime;
+               printTime("ld64 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",           fStartLoadUndefinesTime -       fStartBuildAtomsTime,           totalTime);
+               printTime(" load undefines",            fStartResolveTime -                     fStartLoadUndefinesTime,        totalTime);
+               printTime(" resolve references",        fStartSortTime -                        fStartResolveTime,                      totalTime);
+               printTime(" sort output",                       fStartWriteTime -                       fStartSortTime,                         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));
+       }
 }
 
 inline void Linker::addAtom(ObjectFile::Atom& atom)
 {
        // add to list of all atoms
        fAllAtoms.push_back(&atom);
-       
+
        // 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++) {
@@ -381,13 +579,13 @@ inline void Linker::addAtom(ObjectFile::Atom& atom)
                if ( reference->hasFromTarget() && reference->isFromTargetUnbound() )
                        fGlobalSymbolTable.require(reference->getFromTargetName());
        }
-       
+
        // 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) ) {
                fGlobalSymbolTable.add(atom);
-               
+
                // update scope based on export list (possible that globals are downgraded to private_extern)
                if ( (scope == ObjectFile::Atom::scopeGlobal) && fOptions.hasExportRestrictList() ) {
                        bool doExport = fOptions.shouldExport(name);
@@ -396,10 +594,10 @@ inline void Linker::addAtom(ObjectFile::Atom& atom)
                        }
                }
        }
-               
+
        // record section orders so output file can have same order
        atom.setSection(Section::find(atom.getSectionName(), atom.getSegment().getName(), atom.isZeroFill()));
-       
+
        // assign order in which this atom was originally seen
        if ( atom.getSortOrder() == 0 )
                fNextSortOrder = atom.setSortOrder(fNextSortOrder);
@@ -407,28 +605,39 @@ inline void Linker::addAtom(ObjectFile::Atom& atom)
 
 inline void Linker::addAtoms(std::vector<class ObjectFile::Atom*>& atoms)
 {
+       bool first = true; // assume all atoms are from same reader
        for (std::vector<ObjectFile::Atom*>::iterator it=atoms.begin(); it != atoms.end(); it++) {
+               if ( first ) {
+                       // update fReadersThatHaveSuppliedAtoms
+                       ObjectFile::Reader* reader = (*it)->getFile();
+                       if ( std::find(fReadersThatHaveSuppliedAtoms.begin(), fReadersThatHaveSuppliedAtoms.end(), reader)
+                                       == fReadersThatHaveSuppliedAtoms.end() ) {
+                               fReadersThatHaveSuppliedAtoms.push_back(reader);
+                       }
+               }
                this->addAtom(**it);
+               first = false;
        }
 }
 
 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 
+
+       // writer can contribute atoms
        this->addAtoms(fOutputFile->getAtoms());
-       
+
        // each reader contributes atoms
        const int readerCount = fInputFiles.size();
        for (int i=0; i < readerCount; ++i) {
                this->addAtoms(fInputFiles[i]->getAtoms());
        }
-       
+
        // 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) {
@@ -436,23 +645,33 @@ void Linker::buildAtomList()
        }
 }
 
+static const char* pathLeafName(const char* path)
+{
+       const char* shortPath = strrchr(path, '/');
+       if ( shortPath == NULL )
+               return path;
+       else
+               return &shortPath[1];
+}
+
 void Linker::loadUndefines()
 {
+       fStartLoadUndefinesTime = mach_absolute_time();
        // 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.getNeededNames(true, undefineNames);
-               const int undefineCount = undefineNames.size();
-               for (int i=0; i < undefineCount; ++i) {
-                       const char* name = undefineNames[i];
+               fGlobalSymbolTable.getNeededNames(false, undefineNames);
+               for(std::vector<const char*>::iterator it = undefineNames.begin(); it != undefineNames.end(); ++it) {
+                       const char* name = *it;
                        ObjectFile::Atom* possibleAtom = fGlobalSymbolTable.find(name);
-                       if ( (possibleAtom == NULL) || (possibleAtom->isWeakDefinition() && (fOptions.outputKind() != Options::kObjectFile)) )
+                       if ( (possibleAtom == NULL)
+                         || ((possibleAtom->getDefinitionKind()==ObjectFile::Atom::kWeakDefinition) && (fOptions.outputKind() != Options::kObjectFile) && (possibleAtom->getScope() == ObjectFile::Atom::scopeGlobal)) )
                                this->addJustInTimeAtoms(name);
                }
        }
-       
+
        if ( fOptions.outputKind() != Options::kObjectFile ) {
                // error out on any remaining undefines
                bool doPrint = true;
@@ -480,16 +699,7 @@ void Linker::loadUndefines()
                                fprintf(stderr, "can't resolve symbols:\n");
                                for (int i=0; i < unresolvableCount; ++i) {
                                        const char* name = unresolvableUndefines[i];
-                                       const unsigned int nameLen = strlen(name);
                                        fprintf(stderr, "  %s, referenced from:\n", name);
-                                       char stubName[nameLen+6];
-                                       strcpy(stubName, name);
-                                       strcat(stubName, "$stub");
-                                       char nonLazyName[nameLen+16];
-                                       strcpy(nonLazyName, name);
-                                       strcat(nonLazyName, "$non_lazy_ptr");
-                                       ObjectFile::Atom* lastStubAtomWithUnresolved = NULL;
-                                       ObjectFile::Atom* lastNonLazyAtomWithUnresolved = NULL;
                                        // scan all atoms for references
                                        bool foundAtomReference = false;
                                        for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
@@ -498,50 +708,14 @@ void Linker::loadUndefines()
                                                for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
                                                        ObjectFile::Reference* reference = *rit;
                                                        if ( reference->isTargetUnbound() ) {
-                                                               if ( (atom != lastStubAtomWithUnresolved) && (strcmp(reference->getTargetName(), stubName) == 0) ) {
-                                                                       const char* path = atom->getFile()->getPath();
-                                                                       const char* shortPath = strrchr(path, '/');
-                                                                       if ( shortPath == NULL )
-                                                                               shortPath = path;
-                                                                       else
-                                                                               shortPath = &shortPath[1];
-                                                                       fprintf(stderr, "      %s in %s\n", atom->getDisplayName(), shortPath);
-                                                                       lastStubAtomWithUnresolved = atom;
-                                                                       foundAtomReference = true;
-                                                               }
-                                                               else if ( (atom != lastNonLazyAtomWithUnresolved) && (strcmp(reference->getTargetName(), nonLazyName) == 0) ) {
-                                                                       const char* path = atom->getFile()->getPath();
-                                                                       const char* shortPath = strrchr(path, '/');
-                                                                       if ( shortPath == NULL )
-                                                                               shortPath = path;
-                                                                       else
-                                                                               shortPath = &shortPath[1];
-                                                                       fprintf(stderr, "      %s in %s\n", atom->getDisplayName(), shortPath);
-                                                                       lastNonLazyAtomWithUnresolved = atom;
+                                                               if ( strcmp(reference->getTargetName(), name) == 0 ) {
+                                                                       fprintf(stderr, "      %s in %s\n", atom->getDisplayName(), pathLeafName(atom->getFile()->getPath()));
                                                                        foundAtomReference = true;
                                                                }
                                                        }
                                                        if ( reference->hasFromTarget() && reference->isFromTargetUnbound() ) {
-                                                               if ( (atom != lastStubAtomWithUnresolved) && (strcmp(reference->getFromTargetName(), stubName) == 0) ) {
-                                                                       const char* path = atom->getFile()->getPath();
-                                                                       const char* shortPath = strrchr(path, '/');
-                                                                       if ( shortPath == NULL )
-                                                                               shortPath = path;
-                                                                       else
-                                                                               shortPath = &shortPath[1];
-                                                                       fprintf(stderr, "      %s in %s\n", atom->getDisplayName(), shortPath);
-                                                                       lastStubAtomWithUnresolved = atom;
-                                                                       foundAtomReference = true;
-                                                               }
-                                                               else if ( (atom != lastNonLazyAtomWithUnresolved) && (strcmp(reference->getFromTargetName(), nonLazyName) == 0) ) {
-                                                                       const char* path = atom->getFile()->getPath();
-                                                                       const char* shortPath = strrchr(path, '/');
-                                                                       if ( shortPath == NULL )
-                                                                               shortPath = path;
-                                                                       else
-                                                                               shortPath = &shortPath[1];
-                                                                       fprintf(stderr, "      %s in %s\n", atom->getDisplayName(), shortPath);
-                                                                       lastNonLazyAtomWithUnresolved = atom;
+                                                               if ( strcmp(reference->getFromTargetName(), name) == 0 ) {
+                                                                       fprintf(stderr, "      %s in %s\n", atom->getDisplayName(), pathLeafName(atom->getFile()->getPath()));
                                                                        foundAtomReference = true;
                                                                }
                                                        }
@@ -557,7 +731,7 @@ void Linker::loadUndefines()
                        if ( doError && (unresolvableCount > unresolvableExportsCount) ) // last check should be removed.  It exists so broken projects still build
                                throw "symbol(s) not found";
                }
-               
+
                // now verify that -init routine exists
                if ( fOptions.initFunctionName() != NULL ) {
                        if ( fGlobalSymbolTable.find(fOptions.initFunctionName()) == NULL )
@@ -570,29 +744,33 @@ void Linker::loadUndefines()
 
 void Linker::addJustInTimeAtoms(const char* name)
 {
-       // when creating final linked image, write gets first chance
+       // when creating final linked image, writer gets first chance
        if ( fOptions.outputKind() != Options::kObjectFile ) {
-               ObjectFile::Atom* atom = fOutputFile->getUndefinedProxyAtom(name);
-               if ( atom != NULL ) {
-                       this->addAtom(*atom);\
-                       return;
-               }
-       }
-       
-       // give direct readers a chance
-       const int readerCount = fInputFiles.size();
-       for (int i=0; i < readerCount; ++i) {
-               // 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.
-               std::vector<class ObjectFile::Atom*>* atoms = fInputFiles[i]->getJustInTimeAtomsFor(name);
+               std::vector<class ObjectFile::Atom*>* atoms = fOutputFile->getJustInTimeAtomsFor(name);
                if ( atoms != NULL ) {
                        this->addAtoms(*atoms);
                        delete atoms;
+                       //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, fOutputFile->getPath() );
                        return;  // found a definition, no need to search anymore
-                       //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file #%d\n", name, i);
                }
        }
-       
+
+       // give direct 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.
+                       std::vector<class ObjectFile::Atom*>* atoms = reader->getJustInTimeAtomsFor(name);
+                       if ( atoms != NULL ) {
+                               this->addAtoms(*atoms);
+                               delete atoms;
+                               //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file %s\n", name, fInputFiles[i]->getPath() );
+                               return;  // found a definition, no need to search anymore
+                       }
+               }
+       }
+
        // give indirect readers a chance
        for (std::list<IndirectLibrary>::iterator it=fIndirectDynamicLibraries.begin(); it != fIndirectDynamicLibraries.end(); it++) {
                ObjectFile::Reader* reader = it->reader;
@@ -600,107 +778,37 @@ void Linker::addJustInTimeAtoms(const char* name)
                        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() );
                                delete atoms;
-                               break;
-                               //fprintf(stderr, "addJustInTimeAtoms(%s) => found in file #%d\n", name, i);
+                               return;  // found a definition, no need to search anymore
                        }
                }
        }
-       
+
        // when creating .o file, writer goes last (this is so any static archives will be searched above)
-       if ( fOptions.outputKind() == Options::kObjectFile ) {
+       if ( (fOptions.outputKind() == Options::kObjectFile) || (fOptions.undefinedTreatment() != Options::kUndefinedError) ) {
                ObjectFile::Atom* atom = fOutputFile->getUndefinedProxyAtom(name);
                if ( atom != NULL ) {
                        this->addAtom(*atom);
                        return;
                }
        }
-
+       //fprintf(stderr, "addJustInTimeAtoms(%s) => not found\n", name);
 }
 
 void Linker::resolve(ObjectFile::Reference* reference)
 {
-       ObjectFile::Atom* target = NULL;
-       const char* targetName = reference->getTargetName();
-       const int targetNameLen = strlen(targetName);
-       if ( (targetNameLen > 5) && (strcmp(&targetName[targetNameLen-5], "$stub") == 0) ) {
-               // when looking up "_foo$stub", first look for "_foo"
-               char nonStubTarget[targetNameLen+1];
-               strcpy(nonStubTarget, targetName);
-               nonStubTarget[targetNameLen-5] = '\0';
-               // unless interposing and the symbol is exported 
-               if ( !fOptions.interposable() || !fOptions.shouldExport(nonStubTarget) ) {
-                       target = fGlobalSymbolTable.find(nonStubTarget);        
-                       // also need indirection to all exported weak symbols for C++ support
-                       if ( (target != NULL) && !target->isImportProxy() && (!target->isWeakDefinition() || (target->getScope() != ObjectFile::Atom::scopeGlobal)) ) {
-                               reference->setTarget(*target, reference->getTargetOffset());
-                               // mark stub as no longer being needed
-                               ObjectFile::Atom* stub = fGlobalSymbolTable.find(targetName);
-                               if ( stub != NULL ) {
-                                       char lazySymbol[targetNameLen+8];
-                                       strcpy(lazySymbol, nonStubTarget);
-                                       strcat(lazySymbol, "$lazy_ptr");
-                                       ObjectFile::Atom* lazyPtr = fGlobalSymbolTable.find(lazySymbol);
-                                       fDeadAtoms.insert(stub);
-                                       if ( lazyPtr != NULL )
-                                               fDeadAtoms.insert(lazyPtr);
-                               }
-                               return;
-                       }
-               }
-       }
-       
        // look in global symbol table
-       target = fGlobalSymbolTable.find(targetName);
+       const char* targetName = reference->getTargetName();
+       ObjectFile::Atom* target = fGlobalSymbolTable.find(targetName);
        if ( target == NULL ) {
                fprintf(stderr, "can't resolve: %s\n", targetName);
        }
        reference->setTarget(*target, reference->getTargetOffset());
-       
-       // handle weak-imports
-       if ( target->isImportProxy() ) {
-               bool mismatch = false;
-               if ( reference->isWeakReference() ) {
-                       switch(target->getImportWeakness()) {
-                               case ObjectFile::Atom::kWeakUnset:
-                                       target->setImportWeakness(true);        
-                                       break;
-                               case ObjectFile::Atom::kWeakImport:
-                                       break;
-                               case ObjectFile::Atom::kNonWeakImport:
-                                       mismatch = true;
-                                       break;
-                       }
-               }
-               else {
-                       switch(target->getImportWeakness()) {
-                               case ObjectFile::Atom::kWeakUnset:
-                                       target->setImportWeakness(false);
-                                       break;  
-                               case ObjectFile::Atom::kWeakImport:
-                                       mismatch = true;
-                                       break;
-                               case ObjectFile::Atom::kNonWeakImport:
-                                       break;
-                       }
-               }
-               if ( mismatch ) {
-                       switch ( fOptions.weakReferenceMismatchTreatment() ) {
-                               case Options::kWeakReferenceMismatchError:
-                                       throwf("mismatching weak references for symbol: %s", target->getName());
-                               case Options::kWeakReferenceMismatchWeak:
-                                       target->setImportWeakness(true);
-                                       break;
-                               case Options::kWeakReferenceMismatchNonWeak:
-                                       target->setImportWeakness(false);
-                                       break;
-                       }
-               }
-       }
 }
 
 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);
@@ -713,15 +821,16 @@ void Linker::resolveFrom(ObjectFile::Reference* reference)
 
 void Linker::resolveReferences()
 {
+       fStartResolveTime = mach_absolute_time();
        // 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->isTargetUnbound() ) 
+                       if ( reference->isTargetUnbound() )
                                this->resolve(reference);
-                       if ( reference->hasFromTarget() && reference->isFromTargetUnbound() ) 
+                       if ( reference->hasFromTarget() && reference->isFromTargetUnbound() )
                                this->resolveFrom(reference);
                }
        }
@@ -731,31 +840,112 @@ class InSet
 {
 public:
        InSet(std::set<ObjectFile::Atom*>& deadAtoms) : fDeadAtoms(deadAtoms) {}
-       
-       bool operator()(ObjectFile::Atom*& atom) const { 
+
+       bool operator()(ObjectFile::Atom*& atom) const {
                return ( fDeadAtoms.count(atom) != 0 );
        }
-       
+
 private:
        std::set<ObjectFile::Atom*>& fDeadAtoms;
 };
 
+// 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 DeadStrippable
+{
+public:
+       DeadStrippable()  {}
+
+       bool operator()(ObjectFile::Atom*& atom) const {
+               //if ( ! atom->dontDeadStrip() )
+               //      fprintf(stderr, "dead strip %s\n", atom->getDisplayName());
+               return ( ! atom->dontDeadStrip() );
+       }
+};
+
+void Linker::markLive(ObjectFile::Atom* atom, std::set<ObjectFile::Atom*>& liveAtoms)
+{
+       if ( liveAtoms.count(atom) == 0 ) {
+               // this atom is live
+               liveAtoms.insert(atom);
+               // so don't dead strip
+               atom->setDontDeadStrip();
+
+               // 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;
+                       // mark target of reference as live
+                       this->markLive(&reference->getTarget(), liveAtoms);
+                       // mark from-target (if it exists) as live
+                       if ( reference->hasFromTarget() )
+                               this->markLive(&reference->getFromTarget(), liveAtoms);
+               }
+       }
+}
 
 void Linker::deadStrip()
 {
-       //printf("Stripping atoms:\n");
-       //for (std::set<ObjectFile::Atom*>::iterator it=fDeadAtoms.begin(); it != fDeadAtoms.end(); it++) {
-       //      printf("\t%s\n", (*it)->getDisplayName());
-       //}
+       if ( fOptions.deadStrip() != Options::kDeadStripOff ) {
+               std::set<ObjectFile::Atom*> liveAtoms;
+
+               // mark main() and all atoms reachable from it as live
+               ObjectFile::Atom* entryPoint = this->entryPoint();
+               if ( entryPoint != NULL )
+                       markLive(entryPoint, liveAtoms);
+
+               ObjectFile::Atom* dyldHelper = this->dyldHelper();
+               if ( dyldHelper != NULL )
+                       markLive(dyldHelper, liveAtoms);
+
+               // mark initializers and all atoms reachable from them as live
+               // mark all exported atoms and atoms reachable from them as live
+               Section* initSection = Section::find("__mod_init_func", "__DATA", false);
+               Section* termSection = Section::find("__mod_term_func", "__DATA", false);
+               const bool globalsAreRoots = ( fOptions.outputKind() != Options::kDynamicExecutable );
+               for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
+                       ObjectFile::Atom* atom = *it;
+                       //fprintf(stderr,"%d %s\n", atom->dontDeadStrip(), atom->getDisplayName());
+                       if ( (globalsAreRoots && (atom->getScope() == ObjectFile::Atom::scopeGlobal))
+                               || (atom->getSection() == initSection) || (atom->getSection() == termSection) )
+                               markLive(atom, liveAtoms);
+               }
+
+               // now remove dead strippable atoms from fAllAtoms
+               fAllAtoms.erase(std::remove_if(fAllAtoms.begin(), fAllAtoms.end(), DeadStrippable()), fAllAtoms.end());
+       }
+       else {
+               //printf("Stripping atoms:\n");
+               //for (std::set<ObjectFile::Atom*>::iterator it=fDeadAtoms.begin(); it != fDeadAtoms.end(); it++) {
+               //      printf("\t%s\n", (*it)->getDisplayName());
+               //}
 
-       // for now, just remove atoms weak atoms that have been overridden
-       fAllAtoms.erase(std::remove_if(fAllAtoms.begin(), fAllAtoms.end(), InSet(fDeadAtoms)), fAllAtoms.end());
+               // if not dead stripping, just remove atoms weak atoms that have been overridden
+               fAllAtoms.erase(std::remove_if(fAllAtoms.begin(), fAllAtoms.end(), InSet(fDeadAtoms)), fAllAtoms.end());
+       }
 }
 
 
 
 void Linker::sortAtoms()
 {
+       fStartSortTime = mach_absolute_time();
        Section::assignIndexes();
        std::sort(fAllAtoms.begin(), fAllAtoms.end(), Linker::AtomSorter());
        //fprintf(stderr, "Sorted atoms:\n");
@@ -771,7 +961,130 @@ void Linker::tweakLayout()
 {
 }
 
-void Linker::writeOutput()
+
+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();
+                                       // don't create nodes for stubs, lazy pointers or non-lazy pointers
+                                       const char* lastDollar = strrchr(name, '$');
+                                       if ( lastDollar != NULL ) {
+                                               if ( (strcmp(lastDollar, "$stub") == 0) || (strcmp(lastDollar, "$lazy_ptr") == 0) || (strcmp(lastDollar, "$non_lazy_ptr") == 0) )
+                                                       continue;
+                                       }
+                                       if ( (atom->getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
+                                         || (atom->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
+                                               char temp[strlen(name)+2];
+                                               strcpy(temp, name);
+                                               temp[strlen(name)-7] = '\0'; // strip trailing "$import"
+                                               fprintf(out, "\t%s [ shape = plaintext ];\n", temp);
+                                       }
+                                       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);
+                                                       const char* toName = toAtom->getDisplayName();
+                                                       const char* lastDollar = strrchr(toName, '$');
+                                                       if ( (lastDollar != NULL) && (strcmp(lastDollar, "$stub") == 0) ) {
+                                                               char temp[strlen(toName)+2];
+                                                               strcpy(temp, toName);
+                                                               temp[strlen(toName)-5] = '\0'; // strip trailing "$stub"
+                                                               fprintf(out, "\taddr%p -> %s;\n", fromAtom, temp);
+                                                       }
+                                                       else if ( lastDollar != NULL && (strcmp(lastDollar, "$non_lazy_ptr") == 0) ) {
+                                                               ObjectFile::Atom* nonLazyTargetAtom = &(toAtom->getReferences()[0]->getTarget());
+                                                               if ( (nonLazyTargetAtom->getDefinitionKind() == ObjectFile::Atom::kExternalDefinition)
+                                                                 || (nonLazyTargetAtom->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
+                                                                       char temp[strlen(toName)+2];
+                                                                       strcpy(temp, toName);
+                                                                       temp[strlen(toName)-13] = '\0'; // strip trailing "$non_lazy_ptr"
+                                                                       fprintf(out, "\taddr%p -> %s;\n", fromAtom, temp);
+                                                               }
+                                                               else {
+                                                                       fprintf(out, "\taddr%p -> addr%p;\n", fromAtom, nonLazyTargetAtom);
+                                                               }
+                                                       }
+                                                       else {
+                                                               // don't list references from stubs, lazy pointers or non-lazy pointers
+                                                               const char* name = fromAtom->getDisplayName();
+                                                               const char* lastDollar = strrchr(name, '$');
+                                                               if ( lastDollar != NULL ) {
+                                                                       if ( (strcmp(lastDollar, "$stub") == 0) || (strcmp(lastDollar, "$lazy_ptr") == 0) || (strcmp(lastDollar, "$non_lazy_ptr") == 0) )
+                                                                               continue;
+                                                               }
+                                                               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) ) {
+                                               const char* name = atom->getDisplayName();
+                                               char temp[strlen(name)+2];
+                                               strcpy(temp, name);
+                                               temp[strlen(name)-7] = '\0'; // strip trailing "$import"
+                                               fprintf(out, "%s; ", temp);
+                                       }
+                       }
+                       fprintf(out, "};\n ");
+
+                       // print footer
+                       fprintf(out, "}\n");
+                       fclose(out);
+               }
+               else {
+                       fprintf(stderr, "ld64 warning: could not write dot output file: %s\n", dotOutFilePath);
+               }
+       }
+}
+
+ObjectFile::Atom* Linker::entryPoint()
 {
        // if main executable, find entry point atom
        ObjectFile::Atom* entryPoint = NULL;
@@ -797,13 +1110,495 @@ void Linker::writeOutput()
                        entryPoint = NULL;
                        break;
        }
+       return entryPoint;
+}
+
+ObjectFile::Atom* Linker::dyldHelper()
+{
+       return fGlobalSymbolTable.find("dyld_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)
+{
+       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());
+       // Find all (possibly nested) BINCL/EINCL ranges and their checksums
+       std::vector<HeaderRange> ranges;
+       int curRangeIndex = -1;
+       int count = 0;
+       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 ) {
+                                       fprintf(stderr, "ld64 warning: EINCL missing BINCL in %s\n", 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:
+                       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() )
+                                               fprintf(stderr, "ld64: cannot do BINCL/EINCL optimzation because of stabs kinds in %s for %s\n", ranges[curRangeIndex].begin->string, reader->getPath());
+                               }
+                               break;
+                       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 )
+               fprintf(stderr, "ld64 warning: BINCL (%s) missing EINCL in %s\n", ranges[curRangeIndex].begin->string, reader->getPath());
+               
+       // if no BINCLs
+       if ( ranges.size() == 0 ) {
+               if ( minimal ) {
+                       // only copy minimal stabs
+                       for(std::vector<ObjectFile::Reader::Stab>::iterator it=readerStabs->begin(); it != readerStabs->end(); ++it) {
+                               if ( minimizeStab(*it) )
+                                       fStabs.push_back(*it);
+                       }
+               }
+               else {
+                       // copy all stabs
+                       fStabs.insert(fStabs.end(), readerStabs->begin(), readerStabs->end());
+               }
+               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);
+       //}
        
-       // tell writer about each segment's atoms
-       fOutputFile->write(fAllAtoms, entryPoint);
+       // 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();
+       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 ) {
+                                       if ( !minimal || minimizeStab(*it) )
+                                               fStabs.push_back(*it);
+                               }
+               }
+       }
+
 }
 
 
+void Linker::synthesizeStabs(ObjectFile::Reader* reader)
+{
+       // synthesize "debug notes" and add them to master stabs vector
+       const char* dirPath = NULL;
+       const char* filename = NULL;
+       bool wroteStartSO = false;
+       std::vector<const char*> seenFiles;
+       for (std::vector<class ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); ++it) {
+               ObjectFile::Atom* atom = *it;
+               if ( atom->getFile() == reader ) {
+                       const char* name = atom->getName();
+                       if ( (name != NULL) && (name[0] == '_' ) && (atom->getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn) ) {
+                               const char* newDirPath;
+                               const char* newFilename;
+                               if ( atom->getTranslationUnitSource(&newDirPath, &newFilename) ) {
+                                       // need SO's whenever the translation unit source file changes
+                                       if ( newFilename != filename ) {
+                                               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;
+                                               objStab.other           = 0;
+                                               objStab.desc            = 1;
+                                               objStab.value           = reader->getModificationTime();
+                                               objStab.string          = assureFullPath(reader->getPath());
+                                               fStabs.push_back(objStab);
+                                               wroteStartSO = true;
+                                       }
+                                       filename = newFilename;
+                                       dirPath = newDirPath;
+                                       seenFiles.push_back(filename);
+                                       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         = name;
+                                               fStabs.push_back(startFun);
+                                               // Synthesize any SOL stabs needed
+                                               std::vector<ObjectFile::LineInfo>* lineInfo = atom->getLineInfo();
+                                               if ( lineInfo != NULL ) {
+                                                       // might be nice to set the source file path to seenFiles so it does not show up in SOLs
+                                                       const char* curFile = NULL;
+                                                       for (std::vector<ObjectFile::LineInfo>::iterator it = lineInfo->begin(); it != lineInfo->end(); ++it) {
+                                                               if ( it->fileName != curFile ) {
+                                                                       bool alreadySeen = false;
+                                                                       for (std::vector<const char*>::iterator sit = seenFiles.begin(); sit != seenFiles.end(); ++sit) {
+                                                                               if ( strcmp(it->fileName, *sit) == 0 ) {
+                                                                                       alreadySeen = true;
+                                                                                       break;
+                                                                               }
+                                                                       }
+                                                                       if ( ! alreadySeen ) {
+                                                                               seenFiles.push_back(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 {
+                                               ObjectFile::Reader::Stab globalsStab;
+                                               if ( atom->getScope() == ObjectFile::Atom::scopeTranslationUnit ) {
+                                                       // Synthesize STSYM stab for statics
+                                                       const char* name = atom->getName();
+                                                       if ( name[0] == '_' ) {
+                                                               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 (but not .eh exception frame symbols)
+                                                       const char* name = atom->getName();
+                                                       if ( (name[0] == '_') && (strcmp(atom->getSectionName(), "__eh_frame") != 0) ) {
+                                                               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::collectStabs()
+{
+       if ( fOptions.readerOptions().fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone ) {
+               fStabs.reserve(1024); // try to minimize re-allocations
+               // 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::kDebugInfoNone:
+                                               // do nothing
+                                               break;
+                                       case ObjectFile::Reader::kDebugInfoStabs:
+                                               collectStabs(reader);
+                                               break;
+                                       case ObjectFile::Reader::kDebugInfoDwarf:
+                                               synthesizeStabs(reader);
+                                               fCreateUUID = true;
+                                               break;
+                                   case ObjectFile::Reader::kDebugInfoStabsUUID:
+                                               collectStabs(reader);
+                                               fCreateUUID = true;
+                                               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()
+{
+       fStartWriteTime = mach_absolute_time();
+       // tell writer about each segment's atoms
+       fOutputFileSize = fOutputFile->write(fAllAtoms, fStabs, this->entryPoint(), this->dyldHelper(), (fCreateUUID && fOptions.emitUUID()));
+}
 
 ObjectFile::Reader* Linker::createReader(const Options::FileInfo& info)
 {
@@ -814,30 +1609,69 @@ ObjectFile::Reader* Linker::createReader(const Options::FileInfo& info)
                throwf("can't open file, errno=%d", errno);
        if ( info.fileLen < 20 )
                throw "file too small";
-               
-       char* p = (char*)::mmap(NULL, info.fileLen, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
-       if ( p == (char*)(-1) )
+
+       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);
-       ::close(fd);
-       
+
        // if fat file, skip to architecture we want
-       const mach_header* mh = (mach_header*)p;
-       if ( mh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
+       const fat_header* fh = (fat_header*)p;
+       if ( fh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
                // Fat header is always big-endian
-               const struct fat_header* fh = (struct fat_header*)p;
                const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
                for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
-                       if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)fOptions.architecture() ) {
-                               mh = (struct mach_header*)((char*)p + OSSwapBigToHostInt32(archs[i].offset));
+                       if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)fArchitecture ) {
+                               uint32_t fileOffset = OSSwapBigToHostInt32(archs[i].offset);
                                len = OSSwapBigToHostInt32(archs[i].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];
+                               }
                                break;
                        }
                }
        }
-       
-       if ( mh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
+       ::close(fd);
+
+       switch (fArchitecture) {
+               case CPU_TYPE_POWERPC:
+                       if ( mach_o::relocatable::Reader<ppc>::validFile(p) )
+                               return this->addObject(mach_o::relocatable::Reader<ppc>::make(p, info.path, info.modTime, fOptions.readerOptions()), info, len);
+                       else if ( mach_o::dylib::Reader<ppc>::validFile(p) )
+                               return this->addDylib(mach_o::dylib::Reader<ppc>::make(p, len, info.path, fOptions.readerOptions()), info, len);
+                       else if ( mach_o::archive::Reader<ppc>::validFile(p, len) )
+                               return this->addArchive(mach_o::archive::Reader<ppc>::make(p, len, info.path, info.modTime, fOptions.readerOptions()), info, len);
+                       break;
+               case CPU_TYPE_POWERPC64:
+                       if ( mach_o::relocatable::Reader<ppc64>::validFile(p) )
+                               return this->addObject(mach_o::relocatable::Reader<ppc64>::make(p, info.path, info.modTime, fOptions.readerOptions()), info, len);
+                       else if ( mach_o::dylib::Reader<ppc64>::validFile(p) )
+                               return this->addDylib(mach_o::dylib::Reader<ppc64>::make(p, len, info.path, fOptions.readerOptions()), info, len);
+                       else if ( mach_o::archive::Reader<ppc64>::validFile(p, len) )
+                               return this->addArchive(mach_o::archive::Reader<ppc64>::make(p, len, info.path, info.modTime, fOptions.readerOptions()), info, len);
+                       break;
+               case CPU_TYPE_I386:
+                       if ( mach_o::relocatable::Reader<x86>::validFile(p) )
+                               return this->addObject(mach_o::relocatable::Reader<x86>::make(p, info.path, info.modTime, fOptions.readerOptions()), info, len);
+                       else if ( mach_o::dylib::Reader<x86>::validFile(p) )
+                               return this->addDylib(mach_o::dylib::Reader<x86>::make(p, len, info.path, fOptions.readerOptions()), info, len);
+                       else if ( mach_o::archive::Reader<x86>::validFile(p, len) )
+                               return this->addArchive(mach_o::archive::Reader<x86>::make(p, len, info.path, info.modTime, fOptions.readerOptions()), info, len);
+                       break;
+       }
+
+       // error handling
+       if ( ((fat_header*)p)->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
                const char* archName = "unknown";
-               switch (fOptions.architecture()) {
+               switch (fArchitecture) {
                        case CPU_TYPE_POWERPC:
                                archName = "ppc";
                                break;
@@ -850,86 +1684,15 @@ ObjectFile::Reader* Linker::createReader(const Options::FileInfo& info)
                }
                throwf("missing required architecture %s in fat file", archName);
        }
-       
-       // pull out cpu-type and file-type in endian-safe way
-       cpu_type_t cpuType = 0;
-       uint32_t fileType = 0;
-       if ( mh->magic == MH_MAGIC ) {
-               fileType = mh->filetype;
-               cpuType = mh->cputype;
-       }
-       else if ( mh->magic == OSSwapInt32(MH_MAGIC) ) {
-               fileType = OSSwapInt32(mh->filetype);
-               cpuType = OSSwapInt32(mh->cputype);
-       }
-       else if ( mh->magic == MH_MAGIC_64 ) {
-               fileType = ((mach_header_64*)mh)->filetype;
-               cpuType = ((mach_header_64*)mh)->cputype;
-       }
-       else if ( mh->magic == OSSwapInt32(MH_MAGIC_64) ) {
-               fileType = OSSwapInt32(((mach_header_64*)mh)->filetype);
-               cpuType = OSSwapInt32(((mach_header_64*)mh)->cputype);
-       }
-       else if ( strncmp((const char*)mh, "!<arch>\n", 8) == 0 ) {
-               // is static archive
-               switch ( fOptions.architecture() ) {
-                       case CPU_TYPE_POWERPC:
-                               return ppc::ObjectFileArchiveMachO::MakeReader((const uint8_t*)mh, len, info.path, fOptions.readerOptions());
-                       case CPU_TYPE_POWERPC64:
-                               return ppc64::ObjectFileArchiveMachO::MakeReader((const uint8_t*)mh, len, info.path, fOptions.readerOptions());
-                       case CPU_TYPE_I386:
-                               return i386::ObjectFileArchiveMachO::MakeReader((const uint8_t*)mh, len, info.path, fOptions.readerOptions());
-               }
-               throw "no matching archive reader";
-       }
        else {
-               throw "unknown file type";      
-       }
-       
-       // bail out if cpu-type does not match requrired architecture
-       if ( fOptions.architecture() == cpuType ) {
-               // make appropriate reader object
-               if ( fileType == MH_OBJECT ) {
-                       switch ( cpuType ) {
-                               case CPU_TYPE_POWERPC:
-                                       return ppc::ObjectFileMachO::MakeReader((class ppc::macho_header*)mh, info.path, fOptions.readerOptions());
-                               case CPU_TYPE_POWERPC64:
-                                       return ppc64::ObjectFileMachO::MakeReader((class ppc64::macho_header*)mh, info.path, fOptions.readerOptions());
-                               case CPU_TYPE_I386:
-                                       return i386::ObjectFileMachO::MakeReader((class i386::macho_header*)mh, info.path, fOptions.readerOptions());
-                               default:
-                                       throw "wrong architecture in object file";
-                       }
-               }
-               else if ( (fileType == MH_DYLIB) || (fileType == MH_DYLIB_STUB) ) {
-                       ObjectFile::Reader* dylibReader = NULL;
-                       switch ( cpuType ) {
-                               case CPU_TYPE_POWERPC:
-                                       dylibReader = ppc::ObjectFileDylibMachO::MakeReader((class ppc::macho_header*)mh, info.path, fOptions.readerOptions());
-                                       break;
-                               case CPU_TYPE_POWERPC64:
-                                       dylibReader = ppc64::ObjectFileDylibMachO::MakeReader((class ppc64::macho_header*)mh, info.path, fOptions.readerOptions());
-                                       break;
-                               case CPU_TYPE_I386:
-                                       dylibReader = i386::ObjectFileDylibMachO::MakeReader((class i386::macho_header*)mh, info.path, fOptions.readerOptions());
-                                       break;
-                               default:
-                                       throw "wrong architecture in dylib";
-                       }
-                       this->addDylib(dylibReader, info);
-                       return dylibReader;
-               }
-               throw "unknown mach-o file type";
+               throw "file is not of required architecture";
        }
-       else {
-               throw "file does not contain requested architecture";
-       }
-
 }
 
 
 void Linker::createReaders()
 {
+       fStartCreateReadersTime = mach_absolute_time();
        std::vector<Options::FileInfo>& files = fOptions.getInputFiles();
        const int count = files.size();
        if ( count == 0 )
@@ -957,13 +1720,13 @@ void Linker::createReaders()
                        }
                }
        }
-       
+
        // add first level of indirect dylibs
        fDirectLibrariesComplete = true;
        for (std::vector<ExecutableFile::DyLibUsed>::iterator it=fDynamicLibraries.begin(); it != fDynamicLibraries.end(); it++) {
                this->addIndirectLibraries(it->reader);
        }
-       
+
        // indirect handling depends on namespace
        switch ( fOptions.nameSpace() ) {
                case Options::kFlatNameSpace:
@@ -973,13 +1736,14 @@ void Linker::createReaders()
                        for (std::list<IndirectLibrary>::iterator it=fIndirectDynamicLibraries.begin(); it != fIndirectDynamicLibraries.end(); it++) {
                                try {
                                        it->reader = this->createReader(fOptions.findFile(it->path));
+                                       it->reader->setSortOrder(fNextObjectFileOrder++);
                                }
                                catch (const char* msg) {
                                        fprintf(stderr, "ld64 warning: indirect library %s could not be loaded: %s\n", it->path, msg);
                                }
                        }
                        break;
-                       
+
                case Options::kTwoLevelNameSpace:
                        // with two-level namespace we only want to use indirect libraries that are re-exported through a library that is used
                        {
@@ -991,6 +1755,7 @@ void Linker::createReaders()
                                                if ( it->reader == NULL ) {
                                                        try {
                                                                it->reader = this->createReader(fOptions.findFile(it->path));
+                                                               it->reader->setSortOrder(fNextObjectFileOrder++);
                                                                indirectAdded = true;
                                                        }
                                                        catch (const char* msg) {
@@ -998,55 +1763,174 @@ void Linker::createReaders()
                                                        }
                                                }
                                                // if an indirect library does not have an assigned parent, look for one
-                                               if ( (it->reader != NULL) && (it->reExportParent == NULL) ) {
-                                                       // ask each parent if they re-export this dylib
-                                                       for (std::set<ObjectFile::Reader*>::iterator pit=it->parents.begin(); pit != it->parents.end(); pit++) {
-                                                               if ( (*pit)->reExports(it->reader) ) {
-                                                                       it->reExportParent = *pit;
-                                                                       break;
-                                                               }
-                                                       }
+                                               if ( (it->reader != NULL) && (it->reExportedViaDirectLibrary == NULL) ) {
+                                                       it->reExportedViaDirectLibrary = this->findDirectLibraryWhichReExports(*it);
                                                }
                                        }
                                }
                        }
                        break;
        }
-       
+
        // add relevant indirect libraries to the end of fDynamicLibraries
        for (std::list<IndirectLibrary>::iterator it=fIndirectDynamicLibraries.begin(); it != fIndirectDynamicLibraries.end(); it++) {
-               if ( (it->reExportParent != NULL) || (fOptions.nameSpace() != Options::kTwoLevelNameSpace) ) {
+               if ( (it->reader != NULL) && (it->reExportedViaDirectLibrary != NULL) || (fOptions.nameSpace() != Options::kTwoLevelNameSpace) ) {
                        ExecutableFile::DyLibUsed dylibInfo;
                        dylibInfo.reader = it->reader;
                        dylibInfo.options.fWeakImport = false;
                        dylibInfo.options.fReExport = false;
                        dylibInfo.options.fInstallPathOverride = NULL;
                        dylibInfo.indirect = true;
-                       dylibInfo.directReader = it->reExportParent;
+                       dylibInfo.directReader = it->reExportedViaDirectLibrary;
                        fDynamicLibraries.push_back(dylibInfo);
-                       if ( fOptions.readerOptions().fTraceIndirectDylibs )
-                               printf("[Logging for Build & Integration] Used indirect dynamic library: %s\n", it->reader->getPath());
+                       if ( fOptions.readerOptions().fTraceIndirectDylibs ) {
+                               const char* fullPath = it->reader->getPath();
+                               char realName[MAXPATHLEN];
+                               if ( realpath(fullPath, realName) != NULL )
+                                       fullPath = realName;
+                               logTraceInfo("[Logging for XBS] Used indirect dynamic library: %s\n", fullPath);
+                       }
+               }
+       }
+}
+
+
+ObjectFile::Reader* Linker::findDirectLibraryWhichReExports(IndirectLibrary& indirectLib)
+{
+       // ask each parent if they re-export this dylib
+       for (std::set<ObjectFile::Reader*>::iterator pit=indirectLib.parents.begin(); pit != indirectLib.parents.end(); pit++) {
+               if ( (*pit)->reExports(indirectLib.reader) ) {
+                       ObjectFile::Reader* lib = *pit;
+                       // first check if we found a direct library, if so return it
+                       for (std::vector<ExecutableFile::DyLibUsed>::iterator dit=fDynamicLibraries.begin(); dit != fDynamicLibraries.end(); dit++) {
+                               if ( dit->reader == lib && dit->indirect == false )
+                                       return lib;
+                       }
+                       // otherwise search indirects for parent and see how it is reexported
+                       for (std::list<IndirectLibrary>::iterator iit=fIndirectDynamicLibraries.begin(); iit != fIndirectDynamicLibraries.end(); iit++) {
+                               if ( iit->reader == lib ) {
+                                       ObjectFile::Reader* lib2 = this->findDirectLibraryWhichReExports(*iit);
+                                       if ( lib2 != NULL )
+                                               return lib2;
+                               }
+                       }
                }
        }
+       return NULL;
 }
 
 
 
-void Linker::addDylib(ObjectFile::Reader* reader, const Options::FileInfo& info)
+ObjectFile::Reader* Linker::addArchive(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen)
 {
+       if (fOptions.readerOptions().fTraceArchives) {
+               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);
+       }
+
+       // update stats
+       fTotalArchiveSize += mappedLen;
+       ++fTotalArchivesLoaded;
+       return reader;
+}
+
+ObjectFile::Reader* Linker::addObject(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen)
+{
+       // update stats
+       fTotalObjectSize += mappedLen;
+       ++fTotalObjectLoaded;
+       return reader;
+}
+
+ObjectFile::Reader* Linker::addDylib(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen)
+{
+       if ( reader->getInstallPath() == NULL ) {
+               // this is a "blank" stub
+               // silently ignore it
+               return reader;
+       }
+
        if ( fDirectLibrariesComplete ) {
                this->addIndirectLibraries(reader);
        }
        else {
-               if ( fOptions.readerOptions().fTraceDylibs )
-                       printf("[Logging for Build & Integration] Used dynamic library: %s\n", reader->getPath());
+               if ( fOptions.readerOptions().fTraceDylibs ) {
+                       const char* fullPath = reader->getPath();
+                       char realName[MAXPATHLEN];
+                       if ( realpath(fullPath, realName) != NULL )
+                               fullPath = realName;
+                       logTraceInfo("[Logging for XBS] Used dynamic library: %s\n", fullPath);
+               }
                ExecutableFile::DyLibUsed dylibInfo;
                dylibInfo.reader = reader;
                dylibInfo.options = info.options;
                dylibInfo.indirect = false;
                dylibInfo.directReader = NULL;
                fDynamicLibraries.push_back(dylibInfo);
+       
+
+               // Verify that a client is allowed to link to this dylib.  There are three cases.
+               bool okToLink = true;
+               const char* outputFilePath = fOptions.installPath();
+               const char* outputFilePathLastSlash = strrchr(outputFilePath, '/');
+               if ( reader->parentUmbrella() != NULL ) {
+                       // case 1) The dylib has a parent umbrella, and we are creating the parent umbrella
+                       okToLink = ( (outputFilePathLastSlash != NULL) && (strcmp(&outputFilePathLastSlash[1], reader->parentUmbrella()) == 0) );
+               }
+               
+               if ( !okToLink && (reader->parentUmbrella() != NULL) ) {
+                       // case 2) The dylib has a parent umbrella, and we are creating a sibling with the same parent
+                       okToLink = ( (outputFilePathLastSlash != NULL) 
+                                       && (fOptions.umbrellaName() != NULL) 
+                                       && (strcmp(fOptions.umbrellaName(), reader->parentUmbrella()) == 0) );
+               }
+
+               std::vector<const char*>* clients = reader->getAllowableClients();
+               if ( !okToLink && (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.A.dylib --> foo, Bar.framework/Bar --> Bar)
+                               clientName = outputFilePath;
+                               // starts after last slash
+                               if ( outputFilePathLastSlash != NULL )
+                                       clientName = &outputFilePathLastSlash[1];
+                               if ( strncmp(clientName, "lib", 3) == 0 )
+                                       clientName = &clientName[3];
+                               // up to first dot
+                               const char* firstDot = strchr(clientName, '.');
+                               if ( firstDot == NULL )
+                                       clientNameLen = strlen(clientName);
+                               else
+                                       clientNameLen = firstDot - 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 )
+                                       okToLink = true;
+                       }
+               }
+       
+               // error out if we are not allowed to link
+               if ( ! okToLink )
+                       //throwf("'%s' is a subframework. Link against the umbrella framework '%s.framework' instead.",
+                       fprintf(stderr, "'%s' is a subframework. Link against the umbrella framework '%s.framework' instead.",
+                                       reader->getPath(), reader->parentUmbrella());
        }
+       
+       // update stats
+       ++fTotalDylibsLoaded;
+
+       return reader;
 }
 
 
@@ -1068,7 +1952,7 @@ void Linker::addIndirectLibraries(ObjectFile::Reader* reader)
                                indirectLib.fileLen = 0;
                                indirectLib.reader = NULL;
                                indirectLib.parents.insert(reader);
-                               indirectLib.reExportParent = NULL;
+                               indirectLib.reExportedViaDirectLibrary = NULL;
                                fIndirectDynamicLibraries.push_back(indirectLib);
                                //fprintf(stderr, "add indirect library: %s\n", *it);
                        }
@@ -1104,21 +1988,57 @@ bool Linker::haveDirectLibrary(const char* path)
        return false;
 }
 
+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\n", 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();
        const char* path = fOptions.getOutputFilePath();
-       switch ( fOptions.architecture() ) {
+       switch ( fArchitecture ) {
                case CPU_TYPE_POWERPC:
-                       this->setOutputFile(ppc::ExecutableFileMachO::MakeWriter(path, fOptions, fDynamicLibraries));
+                       this->setOutputFile(new mach_o::executable::Writer<ppc>(path, fOptions, fDynamicLibraries));
                        break;
                case CPU_TYPE_POWERPC64:
-                       this->setOutputFile(ppc64::ExecutableFileMachO::MakeWriter(path, fOptions, fDynamicLibraries));
+                       this->setOutputFile(new mach_o::executable::Writer<ppc64>(path, fOptions, fDynamicLibraries));
                        break;
                case CPU_TYPE_I386:
-                       this->setOutputFile(i386::ExecutableFileMachO::MakeWriter(path, fOptions, fDynamicLibraries));
+                       this->setOutputFile(new mach_o::executable::Writer<x86>(path, fOptions, fDynamicLibraries));
                        break;
                default:
                        throw "unknown architecture";
@@ -1141,132 +2061,194 @@ void Linker::SymbolTable::require(const char* name)
        }
 }
 
-bool Linker::SymbolTable::add(ObjectFile::Atom& atom)
+// convenience labels for 2-dimensional switch statement
+enum {
+       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,
+       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,
+       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,
+       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,
+       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
+};
+
+bool Linker::SymbolTable::add(ObjectFile::Atom& newAtom)
 {
-       const bool log = false;
-       const char* name = atom.getName();
-       //fprintf(stderr, "map.add(%p: %s => %p)\n", &fTable, name, &atom);
+       bool useNew = true;
+       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);
-       if ( pos != fTable.end() ) {
-               ObjectFile::Atom* existingAtom = pos->second;
-               if ( existingAtom != NULL ) {
-                       if ( existingAtom->isTentativeDefinition() ) {
-                               if ( atom.isTentativeDefinition() ) {
-                                       if ( atom.getSize() > existingAtom->getSize() ) {
-                                               // replace common-symbol atom with another larger common-symbol
-                                               if ( fOwner.fOptions.warnCommons() ) 
-                                                       fprintf(stderr, "ld64: replacing common symbol %s size %lld from %s with larger symbol size %lld from %s\n", 
-                                                                       existingAtom->getName(), existingAtom->getSize(), existingAtom->getFile()->getPath(), atom.getSize(), atom.getFile()->getPath());
-                                               fOwner.fDeadAtoms.insert(existingAtom);
-                                               fTable[name] = &atom;
-                                               return true;
-                                       }
-                                       else {
-                                               // keep existing common-symbol atom
-                                               if ( fOwner.fOptions.warnCommons() ) {
-                                                       if ( atom.getSize() == existingAtom->getSize() ) 
-                                                               fprintf(stderr, "ld64: ignoring common symbol %s from %s because already have common from %s with same size\n", 
-                                                                       atom.getName(), atom.getFile()->getPath(), existingAtom->getFile()->getPath());
-                                                       else
-                                                               fprintf(stderr, "ld64: ignoring common symbol %s size %lld from %s because already have larger symbol size %lld from %s\n", 
-                                                                       atom.getName(), atom.getSize(), atom.getFile()->getPath(), existingAtom->getSize(), existingAtom->getFile()->getPath());
-                                               }
-                                               fOwner.fDeadAtoms.insert(&atom);
-                                               return false;
-                                       }
+       ObjectFile::Atom* existingAtom = NULL;
+       if ( pos != fTable.end() )
+               existingAtom = pos->second;
+       if ( existingAtom != NULL ) {
+               // already have atom with same name in symbol table
+               switch ( (existingAtom->getDefinitionKind() << 3) | newAtom.getDefinitionKind() ) {
+                       case kRegAndReg:
+                               throwf("duplicate symbol %s in %s and %s\n", 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;
+                               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 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() > existingAtom->getAlignment() );
+                               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 kTentAndReg:
+                               // replace existing tentative atom with regular one
+                               break;
+                       case kTentAndWeak:
+                               // replace existing tentative atom with weak one ???
+                               break;
+                       case kTentAndTent:
+                               // use largest
+                               if ( newAtom.getSize() < existingAtom->getSize() ) {
+                                       useNew = false;
                                }
-                               else {
-                                       // have common symbol, now found true defintion
-                                       if ( atom.isImportProxy() ) {
-                                               // definition is in a dylib, so commons-mode decides how to handle
-                                               switch ( fOwner.fOptions.commonsMode() ) {
-                                                       case Options::kCommonsIgnoreDylibs:
-                                                               if ( fOwner.fOptions.warnCommons() ) 
-                                                                       fprintf(stderr, "ld64: using common symbol %s from %s and ignoring defintion from dylib %s\n", 
-                                                                                       existingAtom->getName(), existingAtom->getFile()->getPath(), atom.getFile()->getPath());
-                                                               fOwner.fDeadAtoms.insert(&atom);
-                                                               return false;
-                                                       case Options::kCommonsOverriddenByDylibs:
-                                                               if ( fOwner.fOptions.warnCommons() ) 
-                                                                       fprintf(stderr, "ld64: replacing common symbol %s from %s with true definition from %s\n", 
-                                                                                       existingAtom->getName(), existingAtom->getFile()->getPath(), atom.getFile()->getPath());
-                                                               fOwner.fDeadAtoms.insert(existingAtom);
-                                                               fTable[name] = &atom;
-                                                               return true;
-                                                       case Options::kCommonsConflictsDylibsError:
-                                                               throwf("common symbol %s from %s conflicts with defintion from dylib %s", 
-                                                                               existingAtom->getName(), existingAtom->getFile()->getPath(), atom.getFile()->getPath());
-                                               }
-                                       }
-                                       else {
-                                               // replace common-symbol atom with true definition from .o file
-                                               if ( fOwner.fOptions.warnCommons() ) {
-                                                       if ( atom.getSize() < existingAtom->getSize() ) 
-                                                               fprintf(stderr, "ld64: warning: replacing common symbol %s size %lld from %s with smaller true definition size %lld from %s\n", 
-                                                                               existingAtom->getName(), existingAtom->getSize(), existingAtom->getFile()->getPath(), atom.getSize(), atom.getFile()->getPath());
-                                                       else
-                                                               fprintf(stderr, "ld64: replacing common symbol %s from %s with true definition from %s\n", 
-                                                                               existingAtom->getName(), existingAtom->getFile()->getPath(), atom.getFile()->getPath());
-                                               }
-                                               fOwner.fDeadAtoms.insert(existingAtom);
-                                               fTable[name] = &atom;
-                                               return true;
-                                       }
+                               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() )
+                                                       fprintf(stderr, "ld64: using common symbol %s from %s and ignoring defintion from dylib %s\n",
+                                                                       existingAtom->getName(), existingAtom->getFile()->getPath(), newAtom.getFile()->getPath());
+                                               useNew = false;
+                                               break;
+                                       case Options::kCommonsOverriddenByDylibs:
+                                               if ( fOwner.fOptions.warnCommons() )
+                                                       fprintf(stderr, "ld64: replacing common symbol %s from %s with true definition from dylib %s\n",
+                                                                       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());
                                }
-                       }
-                       else if ( atom.isTentativeDefinition() ) {
-                               // keep existing true definition, ignore new tentative definition
-                               if ( fOwner.fOptions.warnCommons() ) {
-                                       if ( atom.getSize() > existingAtom->getSize() ) 
-                                               fprintf(stderr, "ld64: warning: ignoring common symbol %s size %lld from %s because already have definition from %s size %lld, even though definition is smaller\n", 
-                                                       atom.getName(), atom.getSize(), atom.getFile()->getPath(), existingAtom->getFile()->getPath(), existingAtom->getSize());
-                                       else
-                                               fprintf(stderr, "ld64: ignoring common symbol %s from %s because already have definition from %s\n", 
-                                                       atom.getName(), atom.getFile()->getPath(), existingAtom->getFile()->getPath());
+                               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() )
+                                                       fprintf(stderr, "ld64: using common symbol %s from %s and ignoring defintion from dylib %s\n",
+                                                                       newAtom.getName(), newAtom.getFile()->getPath(), existingAtom->getFile()->getPath());
+                                               break;
+                                       case Options::kCommonsOverriddenByDylibs:
+                                               if ( fOwner.fOptions.warnCommons() )
+                                                       fprintf(stderr, "ld64: replacing defintion of %s from dylib %s with common symbol from %s\n",
+                                                                       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());
                                }
-                               fOwner.fDeadAtoms.insert(&atom);
-                               return false;
-                       }
-                       else {
-                               // neither existing nor new atom are tentative definitions
-                               // if existing is weak, we may replace it
-                               if ( existingAtom->isWeakDefinition() ) {
-                                       if ( atom.isImportProxy() ) {
-                                               // keep weak definition even though one exists in a dylib, because coalescing means dylib's copy may not be used
-                                               if ( log ) fprintf(stderr, "keep weak atom even though also in a dylib: %s\n", atom.getName());
-                                               fOwner.fDeadAtoms.insert(&atom);
-                                               return false;
-                                       }
-                                       else if ( atom.isWeakDefinition() ) {
-                                               // have another weak atom, use existing, mark new as dead
-                                               if ( log ) fprintf(stderr, "already have weak atom: %s\n", atom.getName());
-                                               fOwner.fDeadAtoms.insert(&atom);
-                                               return false;
-                                       }
-                                       else {
-                                               // replace weak atom with non-weak atom
-                                               if ( log ) fprintf(stderr, "replacing weak atom %p from %s with %p from %s: %s\n", existingAtom, existingAtom->getFile()->getPath(), &atom, atom.getFile()->getPath(), atom.getName());
-                                               fOwner.fDeadAtoms.insert(existingAtom);
-                                               fTable[name] = &atom;
-                                               return true;
-                                       }
+                               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 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() )
+                                                       fprintf(stderr, "ld64: using common symbol %s from %s and ignoring defintion from dylib %s\n",
+                                                                       newAtom.getName(), newAtom.getFile()->getPath(), existingAtom->getFile()->getPath());
+                                               break;
+                                       case Options::kCommonsOverriddenByDylibs:
+                                               if ( fOwner.fOptions.warnCommons() )
+                                                       fprintf(stderr, "ld64: replacing defintion of %s from dylib %s with common symbol from %s\n",
+                                                                       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());
                                }
-                       }
-                       if ( atom.isWeakDefinition() ) {
-                               // ignore new weak atom, because we already have a non-weak one
-                               return false;
-                       }
-                       if ( atom.isCoalesableByName() && existingAtom->isCoalesableByName() ) {
-                               // both coalesable, so ignore duplicate
-                               return false;
-                       }
-                       fprintf(stderr, "duplicate symbol %s in %s and %s\n", name, atom.getFile()->getPath(), existingAtom->getFile()->getPath());
+                               break;
+                       case kExternWeakAndExtern:
+                               // replace existing weak external with external
+                               break;
+                       case kExternWeakAndExternWeak:
+                               // keep existing external weak
+                               useNew = false;
+                               break;
                }
        }
-       fTable[name] = &atom;
-       return true;
+       if ( useNew ) {
+               fTable[name] = &newAtom;
+               if ( existingAtom != NULL )
+                       fOwner.fDeadAtoms.insert(existingAtom);
+       }
+       else {
+               fOwner.fDeadAtoms.insert(&newAtom);
+       }
+       return useNew;
 }
 
+
+
 ObjectFile::Atom* Linker::SymbolTable::find(const char* name)
 {
        Mapper::iterator pos = fTable.find(name);
@@ -1280,7 +2262,7 @@ ObjectFile::Atom* Linker::SymbolTable::find(const char* name)
 void Linker::SymbolTable::getNeededNames(bool andWeakDefintions, std::vector<const char*>& undefines)
 {
        for (Mapper::iterator it=fTable.begin(); it != fTable.end(); it++) {
-               if ( (it->second == NULL) || (andWeakDefintions && it->second->isWeakDefinition()) ) {
+               if ( (it->second == NULL) || (andWeakDefintions && (it->second->getDefinitionKind()==ObjectFile::Atom::kWeakDefinition)) ) {
                        undefines.push_back(it->first);
                }
        }
@@ -1296,8 +2278,14 @@ bool Linker::AtomSorter::operator()(ObjectFile::Atom* left, ObjectFile::Atom* ri
        unsigned int rightSectionIndex = right->getSection()->getIndex();
        if ( leftSectionIndex != rightSectionIndex)
                return (leftSectionIndex < rightSectionIndex);
-               
-       // with a section, sort by original atom order (.o file order and atom order in .o files)
+
+       // then sort by .o file order
+       ObjectFile::Reader* leftReader = left->getFile();
+       ObjectFile::Reader* rightReader = right->getFile();
+       if ( leftReader !=  rightReader )
+               return leftReader->getSortOrder() < rightReader->getSortOrder();
+
+       // lastly sort by atom within a .o file
        return left->getSortOrder() < right->getSortOrder();
 }
 
@@ -1307,13 +2295,13 @@ int main(int argc, const char* argv[])
        try {
                // create linker object given command line arguments
                Linker ld(argc, argv);
-               
+
                // open all input files
                ld.createReaders();
-               
+
                // open output file
                ld.createWriter();
-               
+
                // do linking
                ld.link();
        }
@@ -1321,13 +2309,7 @@ int main(int argc, const char* argv[])
                fprintf(stderr, "ld64 failed: %s\n", msg);
                return 1;
        }
-       
-       return 0;
-}
-
-
-
-
-
 
 
+       return 0;
+}
diff --git a/src/machochecker.cpp b/src/machochecker.cpp
new file mode 100644 (file)
index 0000000..55f9fd9
--- /dev/null
@@ -0,0 +1,519 @@
+/* -*- 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 <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <mach-o/loader.h>
+#include <mach-o/fat.h>
+#include <mach-o/stab.h>
+
+#include <vector>
+
+#include "MachOFileAbstraction.hpp"
+#include "Architectures.hpp"
+
+
+ __attribute__((noreturn))
+void throwf(const char* format, ...) 
+{
+       va_list list;
+       char*   p;
+       va_start(list, format);
+       vasprintf(&p, format, list);
+       va_end(list);
+       
+       const char*     t = p;
+       throw t;
+}
+
+
+template <typename A>
+class MachOChecker
+{
+public:
+       static bool                                                                     validFile(const uint8_t* fileContent);
+       static MachOChecker<A>*                                         make(const uint8_t* fileContent, uint32_t fileLength, const char* path) 
+                                                                                                               { return new MachOChecker<A>(fileContent, fileLength, path); }
+       virtual                                                                         ~MachOChecker() {}
+
+
+private:
+       typedef typename A::P                                   P;
+       typedef typename A::P::E                                E;
+       typedef typename A::P::uint_t                   pint_t;
+       
+                                                                                               MachOChecker(const uint8_t* fileContent, uint32_t fileLength, const char* path);
+       void                                                                            checkMachHeader();
+       void                                                                            checkLoadCommands();
+       void                                                                            checkSection(const macho_segment_command<P>* segCmd, const macho_section<P>* sect);
+       uint8_t                                                                         loadCommandSizeMask();
+       void                                                                            checkIndirectSymbolTable();
+
+       const char*                                                                     fPath;
+       const macho_header<P>*                                          fHeader;
+       uint32_t                                                                        fLength;
+       const char*                                                                     fStrings;
+       const char*                                                                     fStringsEnd;
+       const macho_nlist<P>*                                           fSymbols;
+       uint32_t                                                                        fSymbolCount;
+       const uint32_t*                                                         fIndirectTable;
+       uint32_t                                                                        fIndirectTableCount;
+
+};
+
+
+
+template <>
+bool MachOChecker<ppc>::validFile(const uint8_t* fileContent)
+{      
+       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_EXECUTE:
+               case MH_DYLIB:
+               case MH_BUNDLE:
+               case MH_DYLINKER:
+                       return true;
+       }
+       return false;
+}
+
+template <>
+bool MachOChecker<ppc64>::validFile(const uint8_t* fileContent)
+{      
+       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_EXECUTE:
+               case MH_DYLIB:
+               case MH_BUNDLE:
+               case MH_DYLINKER:
+                       return true;
+       }
+       return false;
+}
+
+template <>
+bool MachOChecker<x86>::validFile(const uint8_t* fileContent)
+{      
+       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_EXECUTE:
+               case MH_DYLIB:
+               case MH_BUNDLE:
+               case MH_DYLINKER:
+                       return true;
+       }
+       return false;
+}
+
+
+
+template <> uint8_t MachOChecker<ppc>::loadCommandSizeMask()   { return 0x03; }
+template <> uint8_t MachOChecker<ppc64>::loadCommandSizeMask() { return 0x07; }
+template <> uint8_t MachOChecker<x86>::loadCommandSizeMask()   { return 0x03; }
+
+
+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), fIndirectTableCount(0)
+{
+       // sanity check
+       if ( ! validFile(fileContent) )
+               throw "not a mach-o file that can be checked";
+
+       fPath = strdup(path);
+       fHeader = (const macho_header<P>*)fileContent;
+       
+       // sanity check header
+       checkMachHeader();
+       
+       // check load commands
+       checkLoadCommands();
+       
+       checkIndirectSymbolTable();
+
+}
+
+
+template <typename A>
+void MachOChecker<A>::checkMachHeader()
+{
+       if ( (fHeader->sizeofcmds() + sizeof(macho_header<P>)) > fLength )
+               throw "sizeofcmds in mach_header is larger than file";
+       
+       uint32_t flags = fHeader->flags();
+       uint32_t invalidBits = MH_INCRLINK | MH_LAZY_INIT | 0xFFFC0000;
+       if ( flags & invalidBits )
+               throw "invalid bits in mach_header flags";
+               
+}
+
+template <typename A>
+void MachOChecker<A>::checkLoadCommands()
+{
+       // check that all load commands fit within the load command space file
+       const uint8_t* const endOfFile = (uint8_t*)fHeader + fLength;
+       const uint8_t* const endOfLoadCommands = (uint8_t*)fHeader + sizeof(macho_header<P>) + fHeader->sizeofcmds();
+       const uint32_t cmd_count = fHeader->ncmds();
+       const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
+       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 > endOfLoadCommands )
+                       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 macho_segment_command<P>::CMD:
+                       case LC_SYMTAB:
+                       case LC_UNIXTHREAD:
+                       case LC_DYSYMTAB:
+                       case LC_LOAD_DYLIB:
+                       case LC_ID_DYLIB:
+                       case LC_LOAD_DYLINKER:
+                       case LC_ID_DYLINKER:
+                       case macho_routines_command<P>::CMD:
+                       case LC_SUB_FRAMEWORK:
+                       case LC_SUB_UMBRELLA:
+                       case LC_SUB_CLIENT:
+                       case LC_TWOLEVEL_HINTS:
+                       case LC_PREBIND_CKSUM:
+                       case LC_LOAD_WEAK_DYLIB:
+                       case LC_UUID:
+                               break;
+                       default:
+                               throwf("load command #%d is an unknown kind 0x%X", i, cmd->cmd());
+               }
+               cmd = (const macho_load_command<P>*)endOfCmd;
+       }
+       
+       // check segments
+       cmd = cmds;
+       std::vector<std::pair<pint_t, pint_t> > segmentAddressRanges;
+       std::vector<std::pair<pint_t, pint_t> > segmentFileOffsetRanges;
+       const macho_segment_command<P>* linkEditSegment = NULL;
+       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 ( segCmd->cmdsize() != (sizeof(macho_segment_command<P>) + segCmd->nsects() * sizeof(macho_section_content<P>)) )
+                               throw "invalid segment load command size";
+                               
+                       // see if this overlaps another segment address range
+                       uint64_t startAddr = segCmd->vmaddr();
+                       uint64_t endAddr = startAddr + segCmd->vmsize();
+                       for (typename std::vector<std::pair<pint_t, pint_t> >::iterator it = segmentAddressRanges.begin(); it != segmentAddressRanges.end(); ++it) {
+                               if ( it->first < startAddr ) {
+                                       if ( it->second > startAddr )
+                                               throw "overlapping segment vm addresses";
+                               }
+                               else if ( it->first > startAddr ) {
+                                       if ( it->first < endAddr )
+                                               throw "overlapping segment vm addresses";
+                               }
+                               else {
+                                       throw "overlapping segment vm addresses";
+                               }
+                               segmentAddressRanges.push_back(std::make_pair<pint_t, pint_t>(startAddr, endAddr));
+                       }
+                       // see if this overlaps another segment file offset range
+                       uint64_t startOffset = segCmd->fileoff();
+                       uint64_t endOffset = startOffset + segCmd->filesize();
+                       for (typename std::vector<std::pair<pint_t, pint_t> >::iterator it = segmentFileOffsetRanges.begin(); it != segmentFileOffsetRanges.end(); ++it) {
+                               if ( it->first < startOffset ) {
+                                       if ( it->second > startOffset )
+                                               throw "overlapping segment file data";
+                               }
+                               else if ( it->first > startOffset ) {
+                                       if ( it->first < endOffset )
+                                               throw "overlapping segment file data";
+                               }
+                               else {
+                                       throw "overlapping segment file data";
+                               }
+                               segmentFileOffsetRanges.push_back(std::make_pair<pint_t, pint_t>(startOffset, endOffset));
+                               // check is within file bounds
+                               if ( (startOffset > fLength) || (endOffset > fLength) )
+                                       throw "segment file data is past end of file";
+                       }
+                       // verify it fits in file
+                       if ( startOffset > fLength )
+                               throw "segment fileoff does not fit in file";
+                       if ( endOffset > fLength )
+                               throw "segment fileoff+filesize does not fit in file";
+                               
+                       // keep LINKEDIT segment 
+                       if ( strcmp(segCmd->segname(), "__LINKEDIT") == 0 )
+                               linkEditSegment = segCmd;
+                               
+                       // check section ranges
+                       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) {
+                               // check all sections are within segment
+                               if ( sect->addr() < startAddr )
+                                       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 ) {
+                                       if ( sect->offset() < startOffset )
+                                               throwf("section %s file offset not within segment", sect->sectname());
+                                       if ( (sect->offset()+sect->size()) > endOffset )
+                                               throwf("section %s file offset not within segment", sect->sectname());
+                               }       
+                               checkSection(segCmd, sect);
+                       }
+               }
+               cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+       }
+       
+       // verify there was a LINKEDIT segment
+       if ( linkEditSegment == NULL )
+               throw "no __LINKEDIT segment";
+       
+       // checks for executables
+       bool isStaticExecutable = false;
+       if ( fHeader->filetype() == MH_EXECUTE ) {
+               isStaticExecutable = true;
+               cmd = cmds;
+               for (uint32_t i = 0; i < cmd_count; ++i) {
+                       switch ( cmd->cmd() ) {
+                               case LC_LOAD_DYLINKER:
+                                       // the existence of a dyld load command makes a executable dynamic
+                                       isStaticExecutable = false;
+                                       break;
+                       }
+                       cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+               }
+               if ( isStaticExecutable ) {
+                       if ( fHeader->flags() != MH_NOUNDEFS )
+                               throw "invalid bits in mach_header flags for static executable";
+               }
+       }
+
+       // check LC_SYMTAB and LC_DYSYMTAB
+       cmd = cmds;
+       bool foundDynamicSymTab = false;
+       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*)fHeader + symtab->symoff());
+                                       if ( symtab->symoff() < linkEditSegment->fileoff() )
+                                               throw "symbol table not in __LINKEDIT";
+                                       if ( (symtab->symoff() + fSymbolCount*sizeof(macho_nlist<P>*)) > (linkEditSegment->fileoff()+linkEditSegment->filesize()) )
+                                               throw "symbol table end not in __LINKEDIT";
+                                       fStrings = (char*)fHeader + symtab->stroff();
+                                       fStringsEnd = fStrings + symtab->strsize();
+                                       if ( symtab->stroff() < linkEditSegment->fileoff() )
+                                               throw "string pool not in __LINKEDIT";
+                                       if ( (symtab->stroff()+symtab->strsize()) > (linkEditSegment->fileoff()+linkEditSegment->filesize()) )
+                                               throw "string pool extends beyond __LINKEDIT";
+                               }
+                               break;
+                       case LC_DYSYMTAB:
+                               {
+                                       if ( isStaticExecutable )
+                                               throw "LC_DYSYMTAB should not be used in static executable";
+                                       foundDynamicSymTab = true;
+                                       const macho_dysymtab_command<P>* dsymtab = (struct macho_dysymtab_command<P>*)cmd;
+                                       fIndirectTable = (uint32_t*)((char*)fHeader + dsymtab->indirectsymoff());
+                                       fIndirectTableCount = dsymtab->nindirectsyms();
+                                       if ( dsymtab->indirectsymoff() < linkEditSegment->fileoff() )
+                                               throw "indirect symbol table not in __LINKEDIT";
+                                       if ( (dsymtab->indirectsymoff()+fIndirectTableCount*8) > (linkEditSegment->fileoff()+linkEditSegment->filesize()) )
+                                               throw "indirect symbol table not in __LINKEDIT";
+                               }
+                               break;
+               }
+               cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+       }
+       if ( !isStaticExecutable && !foundDynamicSymTab )
+               throw "missing dynamic symbol table";
+       if ( fStrings == NULL )
+               throw "missing symbol table";
+       
+       
+       
+}
+
+template <typename A>
+void MachOChecker<A>::checkSection(const macho_segment_command<P>* segCmd, const macho_section<P>* sect)
+{
+       uint8_t sectionType = (sect->flags() & SECTION_TYPE);
+       if ( sectionType == S_ZEROFILL ) {
+               if ( sect->offset() != 0 )
+                       throwf("section offset should be zero for zero-fill section %s", sect->sectname());
+       }
+       
+       // more section tests here
+}
+
+template <typename A>
+void MachOChecker<A>::checkIndirectSymbolTable()
+{
+       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;
+                       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) {
+                               // make sure all magic sections that use indirect symbol table fit within it
+                               uint32_t start = 0;
+                               uint32_t elementSize = 0;
+                               switch ( sect->flags() & SECTION_TYPE ) {
+                                       case S_SYMBOL_STUBS:
+                                               elementSize = sect->reserved2();
+                                               start = sect->reserved1();
+                                               break;
+                                       case S_LAZY_SYMBOL_POINTERS:
+                                       case S_NON_LAZY_SYMBOL_POINTERS:
+                                               elementSize = sizeof(pint_t);
+                                               start = sect->reserved1();
+                                               break;
+                               }
+                               if ( elementSize != 0 ) {
+                                       uint32_t count = sect->size() / elementSize;
+                                       if ( (count*elementSize) != sect->size() )
+                                               throwf("%s section size is not an even multiple of element size", sect->sectname());
+                                       if ( (start+count) > fIndirectTableCount )
+                                               throwf("%s section references beyond end of indirect symbol table (%d > %d)", sect->sectname(), start+count, fIndirectTableCount );
+                               }
+                       }
+               }
+               cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+       }
+}
+
+
+static void check(const char* path)
+{
+       struct stat stat_buf;
+       
+       try {
+               int fd = ::open(path, O_RDONLY, 0);
+               if ( fd == -1 )
+                       throw "cannot open file";
+               ::fstat(fd, &stat_buf);
+               uint32_t length = stat_buf.st_size;
+               uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE, fd, 0);
+               ::close(fd);
+               const mach_header* mh = (mach_header*)p;
+               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));
+                       for (unsigned long i=0; i < fh->nfat_arch; ++i) {
+                               if ( archs[i].cputype == CPU_TYPE_POWERPC ) {
+                                       if ( MachOChecker<ppc>::validFile(p + archs[i].offset) )
+                                               MachOChecker<ppc>::make(p + archs[i].offset, archs[i].size, path);
+                                       else
+                                               throw "in universal file, ppc slice does not contain ppc mach-o";
+                               }
+                               else if ( archs[i].cputype == CPU_TYPE_I386 ) {
+                                       if ( MachOChecker<x86>::validFile(p + archs[i].offset) )
+                                               MachOChecker<x86>::make(p + archs[i].offset, archs[i].size, path);
+                                       else
+                                               throw "in universal file, i386 slice does not contain i386 mach-o";
+                               }
+                               else if ( archs[i].cputype == CPU_TYPE_POWERPC64 ) {
+                                       if ( MachOChecker<ppc64>::validFile(p + archs[i].offset) )
+                                               MachOChecker<ppc64>::make(p + archs[i].offset, archs[i].size, path);
+                                       else
+                                               throw "in universal file, ppc64 slice does not contain ppc64 mach-o";
+                               }
+                               else {
+                                               throw "in universal file, unknown architecture slice";
+                               }
+                       }
+               }
+               else if ( MachOChecker<x86>::validFile(p) ) {
+                       MachOChecker<x86>::make(p, length, path);
+               }
+               else if ( MachOChecker<ppc>::validFile(p) ) {
+                       MachOChecker<ppc>::make(p, length, path);
+               }
+               else if ( MachOChecker<ppc64>::validFile(p) ) {
+                       MachOChecker<ppc64>::make(p, length, path);
+               }
+               else {
+                       throw "not a known file type";
+               }
+       }
+       catch (const char* msg) {
+               throwf("%s in %s", msg, path);
+       }
+}
+
+
+int main(int argc, const char* argv[])
+{
+       try {
+               for(int i=1; i < argc; ++i) {
+                       const char* arg = argv[i];
+                       if ( arg[0] == '-' ) {
+                               if ( strcmp(arg, "-no_content") == 0 ) {
+                                       
+                               }
+                               else {
+                                       throwf("unknown option: %s\n", arg);
+                               }
+                       }
+                       else {
+                               check(arg);
+                       }
+               }
+       }
+       catch (const char* msg) {
+               fprintf(stderr, "machocheck failed: %s\n", msg);
+               return 1;
+       }
+       
+       return 0;
+}
+
+
+
diff --git a/unit-tests/README b/unit-tests/README
new file mode 100644 (file)
index 0000000..a0fd0a2
--- /dev/null
@@ -0,0 +1,28 @@
+
+The easy way to run all tests is within Xcode.  Just select "unit-tests" as the target and click Build.
+
+When run from within Xcode, the just built linker will be used.  If you cd into a test case and run it, the
+installed linker (e.g. /usr/bin/ld) will be used.
+
+Each test case is a directory with a Makefile.  The Makefile default target should do whatever work is necessary
+to perform the test. If successful is should print "PASS xxx" where xxx is the name of the test case.  Otherwise
+it should print "FAIL xxx reason".  If nothing is printed (for instance a tool crashed), the harness will 
+automatically print that it failed.  The harness will always pass ARCH to the Makefile to specify which 
+architecture to test. The Makefile should also have a "clean" target which removes and generated files.
+
+
+There are some utility functions for use in Makefiles for generating the PASS/FAIL strings:
+
+       ${PASS_IFF} can be put in front of the last command in the make rule and it will print PASS
+       if the command returned 0 or FAIL otherwise.  Example:
+               ${PASS_IFF} ${CC} foo.c -o foo
+       Will print PASS if and only if the compilation succeeded
+               
+       ${PASS_IFF_EMPTY} can have data piped into it.  It prints PASS if there is no data, otherwise FAIL.
+       Example:
+               otool -hv foo.o | grep SUBSECTIONS_VIA_SYMBOLS | ${PASS_IFF_EMPTY}
+       Will print PASS if and only if the output of otool does not contain SUBSECTIONS_VIA_SYMBOLS
+       
+       
+
diff --git a/unit-tests/bin/exit-non-zero-pass.pl b/unit-tests/bin/exit-non-zero-pass.pl
new file mode 100755 (executable)
index 0000000..dd4c3e5
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/perl -w
+
+#
+# Usage:
+#
+#              ${PASS_UNLESS} "test name" command
+#
+
+use strict;
+
+my $string = shift @ARGV;
+
+if(0 == system(@ARGV))
+{
+    printf("FAIL $string\n");
+}
+else
+{
+    printf("PASS $string\n");
+}
+exit 0;
+
diff --git a/unit-tests/bin/fail-if-exit-non-zero.pl b/unit-tests/bin/fail-if-exit-non-zero.pl
new file mode 100755 (executable)
index 0000000..24ca895
--- /dev/null
@@ -0,0 +1,21 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+my $test_name = "";
+if ( exists $ENV{UNIT_TEST_NAME} ) {
+       $test_name = $ENV{UNIT_TEST_NAME};
+}
+
+if(system(@ARGV) != 0)
+{
+    printf("FAIL $test_name\n");
+       exit 1;
+}
+else 
+{
+       exit 0;
+}
+
+
+
diff --git a/unit-tests/bin/fail-if-exit-zero.pl b/unit-tests/bin/fail-if-exit-zero.pl
new file mode 100755 (executable)
index 0000000..f1610c9
--- /dev/null
@@ -0,0 +1,18 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+my $test_name = "";
+if ( exists $ENV{UNIT_TEST_NAME} ) {
+    $test_name = $ENV{UNIT_TEST_NAME};
+}
+
+if(system(@ARGV) == 0)
+{
+    printf("FAIL $test_name\n");
+    exit 1;
+}
+else
+{
+    exit 0;
+}
diff --git a/unit-tests/bin/fail-if-no-stdin.pl b/unit-tests/bin/fail-if-no-stdin.pl
new file mode 100755 (executable)
index 0000000..0c8ae66
--- /dev/null
@@ -0,0 +1,20 @@
+#!/usr/bin/perl -w
+
+#
+# Usage:
+#
+#              command | ${FAIL_IF_EMPTY}
+#
+
+use strict;
+
+my $test_name = "";
+if ( exists $ENV{UNIT_TEST_NAME} ) {
+       $test_name = $ENV{UNIT_TEST_NAME};
+}
+
+if( eof STDIN )
+{
+    printf("FAIL $test_name\n");
+}
+exit 0;
diff --git a/unit-tests/bin/fail-if-stdin.pl b/unit-tests/bin/fail-if-stdin.pl
new file mode 100755 (executable)
index 0000000..f5e2fdf
--- /dev/null
@@ -0,0 +1,24 @@
+#!/usr/bin/perl -w
+
+#
+# Usage:
+#
+#              command | ${FAIL_IF_STDIN}
+#
+
+use strict;
+
+my $test_name = "";
+if ( exists $ENV{UNIT_TEST_NAME} ) {
+       $test_name = $ENV{UNIT_TEST_NAME};
+}
+
+if( eof STDIN )
+{
+
+}
+else
+{
+    printf("FAIL $test_name\n");
+}
+exit 0;
diff --git a/unit-tests/bin/fail-iff-exit-zero.pl b/unit-tests/bin/fail-iff-exit-zero.pl
new file mode 100755 (executable)
index 0000000..f62b797
--- /dev/null
@@ -0,0 +1,25 @@
+#!/usr/bin/perl -w
+
+#
+# Usage:
+#
+#              ${FALL_IFF} command
+#
+
+use strict;
+
+my $test_name = "";
+if ( exists $ENV{UNIT_TEST_NAME} ) {
+       $test_name = $ENV{UNIT_TEST_NAME};
+}
+
+if(0 == system(@ARGV))
+{
+    printf("FAIL $test_name\n");
+}
+else
+{
+    printf("PASS $test_name\n");
+}
+exit 0;
+
diff --git a/unit-tests/bin/make-recursive.pl b/unit-tests/bin/make-recursive.pl
new file mode 100755 (executable)
index 0000000..a441350
--- /dev/null
@@ -0,0 +1,120 @@
+#!/usr/bin/perl 
+
+use strict;
+use Data::Dumper;
+use File::Find;
+use Cwd qw(realpath);
+
+my @args = @ARGV;
+
+my $makefiles =
+{
+    'makefile' => undef,
+    'Makefile' => undef,
+};
+
+my $find_opts =
+{
+    'wanted' => \&find_callback,
+};
+
+my $keywords =
+{
+    'root'   => '',
+    'cwd'    => '',
+    'cmd'    => '',
+    'exit'   => '',
+    'stdout' => [],
+    'stderr' => [],
+};
+
+my $keyword;
+my $max_keyword_len = 0;
+foreach $keyword (keys %$keywords)
+{ if($max_keyword_len < length($keyword)) { $max_keyword_len = length($keyword); } }
+my $delim = ':';
+$max_keyword_len += length($delim) + length(' ');
+
+my $last_keyword = '';
+
+sub print_line
+{
+    my ($keyword, $val) = @_;
+
+    if(!exists($$keywords{$keyword}))
+    {
+       print STDERR "error: keyword $keyword not in \$keywords set\n";
+       exit(1);
+    }
+
+    my $keyword_len = 0;
+
+    if($keyword ne $last_keyword)
+    {
+       print("$keyword"); print($delim);
+       $keyword_len = length($keyword) + length($delim);
+    }
+    if($max_keyword_len > $keyword_len)
+    {
+       my $num_spaces = $max_keyword_len - $keyword_len;
+       print(' ' x $num_spaces);
+    }
+    print("$val");
+    if(0)
+    {
+       $last_keyword = $keyword;
+    }
+}
+
+my $root = '.';
+$root = &realpath($root);
+print_line("root", "$root\n");
+
+find($find_opts, $root);
+
+sub find_callback
+{
+    if(exists($$makefiles{$_}))
+    {
+       my $makefile = $_;
+       my $reldir = $File::Find::dir;
+       $reldir =~ s|^$root/||;
+       
+       &print_line("cwd", "\$root/$reldir\n");
+       my $cmd = [ "make" ];
+       
+       my $arg; foreach $arg (@ARGV) { push @$cmd, $arg; } # better way to do this?
+       &print_line("cmd", "@$cmd\n");
+
+        open(SAVEOUT, ">&STDOUT") || die("$!");
+        open(SAVEERR, ">&STDERR") || die("$!");
+       open(STDOUT, ">/tmp/unit-tests-stdout") || die("$!");
+       open(STDERR, ">/tmp/unit-tests-stderr") || die("$!");
+
+       $ENV{UNIT_TEST_NAME} = $reldir;
+       my $exit = system(@$cmd);
+
+       close(STDOUT) || die("$!");
+       close(STDERR) || die("$!");
+        open(STDOUT, ">&SAVEOUT") || die("$!");
+        open(STDERR, ">&SAVEERR") || die("$!");
+
+       &print_line("exit", "$exit\n");
+
+       open(OUT, "</tmp/unit-tests-stdout") || die("$!");
+       while(<OUT>)
+       {
+           &print_line("stdout", "$_");
+       }
+       close(OUT) || die("$!");
+       unlink("/tmp/unit-tests-stdout");
+       
+       open(ERR, "</tmp/unit-tests-stderr") || die("$!");
+       while(<ERR>)
+       {
+           &print_line("stderr", "$_");
+       }
+       close(ERR) || die("$!");
+    }
+       unlink("/tmp/unit-tests-stderr");
+}
diff --git a/unit-tests/bin/pass-iff-exit-zero.pl b/unit-tests/bin/pass-iff-exit-zero.pl
new file mode 100755 (executable)
index 0000000..ff0f1ed
--- /dev/null
@@ -0,0 +1,25 @@
+#!/usr/bin/perl -w
+
+#
+# Usage:
+#
+#              ${PASS_IFF} command
+#
+
+use strict;
+
+my $test_name = "";
+if ( exists $ENV{UNIT_TEST_NAME} ) {
+       $test_name = $ENV{UNIT_TEST_NAME};
+}
+
+if(0 == system(@ARGV))
+{
+    printf("PASS $test_name\n");
+}
+else
+{
+    printf("FAIL $test_name\n");
+}
+exit 0;
+
diff --git a/unit-tests/bin/pass-iff-no-stdin.pl b/unit-tests/bin/pass-iff-no-stdin.pl
new file mode 100755 (executable)
index 0000000..08903f6
--- /dev/null
@@ -0,0 +1,25 @@
+#!/usr/bin/perl -w
+
+#
+# Usage:
+#
+#              command | ${PASS_IFF_EMPTY} 
+#
+
+use strict;
+
+my $test_name = "";
+if ( exists $ENV{UNIT_TEST_NAME} ) {
+       $test_name = $ENV{UNIT_TEST_NAME};
+}
+
+if( eof STDIN )
+{
+    printf("PASS $test_name\n");
+}
+else
+{
+    printf("FAIL $test_name\n");
+}
+exit 0;
+
diff --git a/unit-tests/bin/pass-iff-stdin.pl b/unit-tests/bin/pass-iff-stdin.pl
new file mode 100755 (executable)
index 0000000..0b56925
--- /dev/null
@@ -0,0 +1,25 @@
+#!/usr/bin/perl -w
+
+#
+# Usage:
+#
+#              command | ${PASS_IFF_STDIN} 
+#
+
+use strict;
+
+my $test_name = "";
+if ( exists $ENV{UNIT_TEST_NAME} ) {
+       $test_name = $ENV{UNIT_TEST_NAME};
+}
+
+if( eof STDIN )
+{
+    printf("FAIL $test_name\n");
+}
+else
+{
+    printf("PASS $test_name\n");
+}
+exit 0;
+
diff --git a/unit-tests/bin/result-filter.pl b/unit-tests/bin/result-filter.pl
new file mode 100755 (executable)
index 0000000..9443452
--- /dev/null
@@ -0,0 +1,127 @@
+#!/usr/bin/perl -w
+
+use strict;
+use Data::Dumper;
+use File::Find;
+use Cwd;
+
+$Data::Dumper::Terse = 1;
+
+my $root = undef;
+my $entry = '';
+my $pass_count = 0;
+my $total_count = 0;
+
+# first match "root: "
+
+# a line starting with "cwd:" marks the beginning of a new test case
+# call process_entry() on each test case
+while(<>)
+{
+    if(m/^root:\s+(.*?)$/)
+    {
+       $root = $1;
+    }
+    elsif(m/^cwd:\s+(.*?)$/)
+    {
+       if(length($entry))
+       {
+           &process_entry($root, $entry);
+           $entry = '';
+       }
+       $entry .= $_;
+    }
+    else
+    {
+       $entry .= $_;
+    }
+}
+# don't forget last test case (no cwd: to mark end)
+if(length($entry))
+{
+    &process_entry($root, $entry);
+}
+
+# show totals
+my $percentage = $pass_count * 100 / $total_count;
+printf " * * * %d of %d unit-tests passed (%.1f percent) * * *\n", $pass_count, $total_count, $percentage;
+
+
+sub process_entry
+{
+    my ($root, $lines) = @_;
+
+    # build an associative array of keys to value(s) 
+    my $lines_seq = [split /\n/, $lines];
+    #print Dumper($lines_seq);
+    my $tbl = { 'root' => $root, 'stdout' => [], 'stderr' => [] };
+    my $line;
+    foreach $line (@$lines_seq)
+    {
+       if($line =~ m/^(\w+):\s+(.*)$/)
+       {
+           my $key = $1;
+           my $val = $2;
+           if(!exists($$tbl{$key}))
+           { $$tbl{$key} = ''; }
+
+           if($key eq 'stdout' || $key eq 'stderr') # if type is @array
+           {
+               push @{$$tbl{$key}}, $val;
+           }
+           else
+           {
+               $$tbl{$key} .= $val;
+           }
+       }
+       else
+       {
+           print "ERROR: $line";
+       }
+    }
+    #print Dumper($tbl);
+    #return;
+
+    my $test_name = $$tbl{cwd};
+    if ($test_name =~ m|.*/([a-zA-Z0-9-+_]+)$|)
+    {
+       $test_name = $1;
+    }
+    
+    #if make failed (exit was non-zero), mark this as a failure
+    if(0 ne $$tbl{exit})
+    {
+       printf "%-40s FAIL Makefile failure\n", $test_name;
+       $total_count++;
+       return;
+    }
+
+    #if there was any output to stderr, mark this as a failure
+    foreach $line (@{$$tbl{stderr}})
+    {
+       printf "%-40s FAIL spurious stderr failure: %s\n", $test_name, $line;
+       $total_count++;
+       return;
+    }
+
+    # scan all stdout looking for lines that start with PASS or FAIL
+    my $seen_result = 0;
+    foreach $line (@{$$tbl{stdout}})
+    {
+       if($line =~ m/^(PASS|XPASS|FAIL|XFAIL).+/)
+       {
+           printf "%-40s %s\n", $test_name, $line;
+           $total_count++;
+           if($line =~ m/^PASS.+/)
+           {
+               $pass_count++;
+           }
+           $seen_result = 1;
+       }
+    }
+    if(!$seen_result)
+    {
+       printf "%-40s AMBIGIOUS missing [X]PASS/[X]FAIL\n", $test_name;
+       $total_count++;
+    }
+}
diff --git a/unit-tests/include/common.makefile b/unit-tests/include/common.makefile
new file mode 100644 (file)
index 0000000..7d41e76
--- /dev/null
@@ -0,0 +1,45 @@
+# stuff to include in every test Makefile
+
+SHELL = /bin/sh
+
+# set default to be host
+ARCH ?= $(shell arch)
+
+# set default to be all
+VALID_ARCHS ?= "ppc ppc64 i386"
+
+# if run within Xcode, add the just built tools to the command path
+ifdef BUILT_PRODUCTS_DIR
+       PATH := ${BUILT_PRODUCTS_DIR}:${PATH}
+endif
+
+LD                     = ld
+OBJECTDUMP     = ObjectDump
+MACHOCHECK     = machocheck
+
+OTOOL = otool
+ifeq (${ARCH},ppc64)
+OTOOL = otool64
+endif
+
+
+CC              = gcc-4.0 -arch ${ARCH}
+CCFLAGS = -Wall -g -std=c99
+ASMFLAGS =
+
+CXX              = g++-4.0 -arch ${ARCH}
+CXXFLAGS = -Wall -g
+
+RM      = rm
+RMFLAGS = -rf
+
+# utilites for Makefiles
+PASS_IFF                       = ${TESTROOT}/bin/pass-iff-exit-zero.pl
+PASS_IFF_EMPTY         = ${TESTROOT}/bin/pass-iff-no-stdin.pl
+PASS_IFF_STDIN         = ${TESTROOT}/bin/pass-iff-stdin.pl
+PASS_IFF_GOOD_MACHO    = ${TESTROOT}/bin/pass-iff-exit-zero.pl ${MACHOCHECK}
+FAIL_IFF                       = ${TESTROOT}/bin/fail-iff-exit-zero.pl
+FAIL_IF_BAD_MACHO      = ${TESTROOT}/bin/fail-if-exit-non-zero.pl ${MACHOCHECK}
+FAIL_IF_SUCCESS         = ${TESTROOT}/bin/fail-if-exit-zero.pl
+FAIL_IF_EMPTY          = ${TESTROOT}/bin/fail-if-no-stdin.pl
+FAIL_IF_STDIN          = ${TESTROOT}/bin/fail-if-stdin.pl
diff --git a/unit-tests/include/test.h b/unit-tests/include/test.h
new file mode 100644 (file)
index 0000000..faca714
--- /dev/null
@@ -0,0 +1,35 @@
+#include <stdarg.h>
+#include <stdio.h>
+
+#define DEFINE_TEST_FUNC(name) \
+  static \
+  inline \
+  void \
+  name(const char *format, ...) \
+  { \
+    va_list args; \
+    va_start(args, format); \
+    common(stdout, #name, format, args); \
+    va_end(args); \
+    return; \
+  }
+
+static
+inline
+void
+common(FILE *file, const char *prefix, const char *format, va_list args)
+{
+  fprintf(file, "%s \"", prefix);
+  vfprintf(file, format, args);
+  fprintf(file, "\"\n"); // should check for trailing newline
+  return;
+}
+
+DEFINE_TEST_FUNC(PASS);
+DEFINE_TEST_FUNC(XPASS);
+DEFINE_TEST_FUNC(FAIL);
+DEFINE_TEST_FUNC(XFAIL);
+
+DEFINE_TEST_FUNC(UNTESTED);
+DEFINE_TEST_FUNC(UNSUPPORTED);
+DEFINE_TEST_FUNC(UNRESOLVED);
diff --git a/unit-tests/run-all-unit-tests b/unit-tests/run-all-unit-tests
new file mode 100755 (executable)
index 0000000..a18560a
--- /dev/null
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+# cd into test-cases directory
+cd `echo "$0" | sed 's/run-all-unit-tests/test-cases/'`
+
+all_archs="ppc ppc64 i386"
+
+for arch in $all_archs
+do
+       echo ""
+       echo " * * * Running all unit tests for architecture $arch * * *"
+
+       # build architecture
+       ../bin/make-recursive.pl ARCH=$arch VALID_ARCHS="$all_archs" | ../bin/result-filter.pl
+
+       # clean up so svn is happy
+       ../bin/make-recursive.pl ARCH=$arch clean > /dev/null
+
+       echo ""
+done
+
+
+
diff --git a/unit-tests/test-cases/allow-stack-execute/Makefile b/unit-tests/test-cases/allow-stack-execute/Makefile
new file mode 100644 (file)
index 0000000..9c2aaba
--- /dev/null
@@ -0,0 +1,46 @@
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test the we set the stack execution bit properly.
+#
+
+run: all
+
+all:
+
+# Test with the flag
+       ${CC} ${CCFLAGS} foo.c -o foo-${ARCH} -Wl,-allow_stack_execute
+       ${FAIL_IF_BAD_MACHO} foo-${ARCH}
+       ${OTOOL} -hv foo-${ARCH} | grep ALLOW_STACK_EXECUTION | ${FAIL_IF_EMPTY}
+       rm -f foo-${ARCH}
+
+# Test without the flag
+       ${CC} ${CCFLAGS} foo.c -o foo-${ARCH}
+       ${FAIL_IF_BAD_MACHO} foo-${ARCH}
+       ${OTOOL} -hv foo-${ARCH} | grep ALLOW_STACK_EXECUTION | ${PASS_IFF_EMPTY}
+
+clean:
+       rm -rf foo-${ARCH}
diff --git a/unit-tests/test-cases/allow-stack-execute/foo.c b/unit-tests/test-cases/allow-stack-execute/foo.c
new file mode 100644 (file)
index 0000000..57ed6ba
--- /dev/null
@@ -0,0 +1,4 @@
+int main (void)
+{
+   return 0;
+}
diff --git a/unit-tests/test-cases/allowable-client/Makefile b/unit-tests/test-cases/allowable-client/Makefile
new file mode 100644 (file)
index 0000000..88e215b
--- /dev/null
@@ -0,0 +1,90 @@
+##
+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test that the -allowable_client and -client options
+# work when linking against subframeworks.
+#
+
+run: all
+
+all:
+# build with two allowable_clients
+       ${CC} ${CCFLAGS} -dynamiclib -umbrella foo -allowable_client bar -allowable_client baz foo.c -o foo.${ARCH}.dylib
+       ${FAIL_IF_BAD_MACHO} foo.${ARCH}.dylib
+
+# test that -o works
+       ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.${ARCH}.dylib foo.${ARCH}.dylib
+       ${FAIL_IF_BAD_MACHO} libbar.${ARCH}.dylib
+
+# test that a framework style output works
+       mkdir -p bar.framework
+       ${CC} ${CCFLAGS} -dynamiclib bar.c -o bar.framework/bar foo.${ARCH}.dylib
+       ${FAIL_IF_BAD_MACHO} bar.framework/bar
+
+# test that second -o works
+       ${CC} ${CCFLAGS} -dynamiclib baz.c -o libbaz.${ARCH}.dylib foo.${ARCH}.dylib
+
+# test that -o and -install_name works with install_name as an allowable
+       ${CC} ${CCFLAGS} -dynamiclib bar.c -o temp.${ARCH}.dylib -install_name /tmp/libbar.${ARCH}.dylib foo.${ARCH}.dylib
+       ${FAIL_IF_BAD_MACHO} temp.${ARCH}.dylib
+
+# test that -o and -install_name fails with install_name different than allowable
+###    ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} -dynamiclib bar.c -o bar.${ARCH}.dylib -install_name /tmp/fail.${ARCH}.dylib foo.${ARCH}.dylib >& fail.log
+
+# test that a bundle and no client_name fails
+###    ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} -bundle bar.c -o temp.${ARCH}.bundle foo.${ARCH}.dylib >& fail.log
+
+# test that a bundle and an allowable client_name passes
+       ${CC} ${CCFLAGS} -bundle bar.c -client_name bar -o bar.${ARCH}.bundle foo.${ARCH}.dylib
+       ${FAIL_IF_BAD_MACHO} bar.${ARCH}.bundle
+
+# test umbrella can link against subs
+       mkdir -p foo.framework
+       ${CC} ${CCFLAGS} -dynamiclib foo.${ARCH}.dylib -o foo.framework/foo
+       ${FAIL_IF_BAD_MACHO} foo.framework/foo
+
+# test sibling in umbrella can link against subs
+       ${CC} ${CCFLAGS} -dynamiclib main.c -umbrella foo foo.${ARCH}.dylib -o ./main.dylib
+       ${FAIL_IF_BAD_MACHO} main.dylib
+
+# test anyone can link against umbrella
+       ${CC} ${CCFLAGS} main.c -o main.${ARCH} -framework foo -F.
+       ${FAIL_IF_BAD_MACHO} main.${ARCH}
+
+# test that an executable and no client_name fails
+###    ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} main.c -o main.${ARCH} foo.${ARCH}.dylib >& fail.log
+
+# test that an executable and an allowable client_name passes
+#      ${CC} ${CCFLAGS} main.c -o main.${ARCH} -client_name bar foo.${ARCH}.dylib
+#      ${PASS_IFF_GOOD_MACHO} main.${ARCH}
+
+       
+# print final pass
+       ${PASS_IFF_GOOD_MACHO} foo.${ARCH}.dylib
+       
+clean:
+
+       rm -rf *.${ARCH}.dylib *.${ARCH}.bundle main.${ARCH} fail.log foo.framework bar.framework main.dylib
diff --git a/unit-tests/test-cases/allowable-client/bar.c b/unit-tests/test-cases/allowable-client/bar.c
new file mode 100644 (file)
index 0000000..dbaeef8
--- /dev/null
@@ -0,0 +1,6 @@
+extern int foo ();
+
+int bar (void)
+{
+  return foo();
+}
diff --git a/unit-tests/test-cases/allowable-client/baz.c b/unit-tests/test-cases/allowable-client/baz.c
new file mode 100644 (file)
index 0000000..dbaeef8
--- /dev/null
@@ -0,0 +1,6 @@
+extern int foo ();
+
+int bar (void)
+{
+  return foo();
+}
diff --git a/unit-tests/test-cases/allowable-client/foo.c b/unit-tests/test-cases/allowable-client/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/allowable-client/main.c b/unit-tests/test-cases/allowable-client/main.c
new file mode 100644 (file)
index 0000000..7b76173
--- /dev/null
@@ -0,0 +1,6 @@
+extern int foo ();
+
+int main (void)
+{
+   return foo();
+}
diff --git a/unit-tests/test-cases/archive-basic/Makefile b/unit-tests/test-cases/archive-basic/Makefile
new file mode 100644 (file)
index 0000000..721cf2a
--- /dev/null
@@ -0,0 +1,46 @@
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is a sanity check that .o files
+# can be found in archives.
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} foo.c -c -o foo-${ARCH}.o 
+       ${CC} ${CCFLAGS} bar.c -c -o bar-${ARCH}.o 
+       libtool -static foo-${ARCH}.o  bar-${ARCH}.o -o libfoobar-${ARCH}.a
+       ${CC} ${CCFLAGS} main.c -lfoobar-${ARCH} -L. -o main-${ARCH} 
+       ${FAIL_IF_BAD_MACHO} main-${ARCH}
+       nm main-${ARCH} | grep "_bar" | ${PASS_IFF_EMPTY}
+       ${CC} ${CCFLAGS} main.c -all_load -lfoobar-${ARCH} -L. -o main-${ARCH} 
+       ${FAIL_IF_BAD_MACHO} main-${ARCH}
+
+clean:
+       rm -rf main-${ARCH} foo-${ARCH}.o bar-${ARCH}.o libfoobar-${ARCH}.a
+       
+
diff --git a/unit-tests/test-cases/archive-basic/bar.c b/unit-tests/test-cases/archive-basic/bar.c
new file mode 100644 (file)
index 0000000..7fe6403
--- /dev/null
@@ -0,0 +1 @@
+int bar() { return 0; }
diff --git a/unit-tests/test-cases/archive-basic/foo.c b/unit-tests/test-cases/archive-basic/foo.c
new file mode 100644 (file)
index 0000000..a60f28c
--- /dev/null
@@ -0,0 +1 @@
+int foo() { return 1; }
diff --git a/unit-tests/test-cases/archive-basic/main.c b/unit-tests/test-cases/archive-basic/main.c
new file mode 100644 (file)
index 0000000..57c4c68
--- /dev/null
@@ -0,0 +1,32 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+extern int foo();
+
+int main()
+{
+       fprintf(stdout, "hello\n");
+       return foo();
+}
\ No newline at end of file
diff --git a/unit-tests/test-cases/archive-weak/Makefile b/unit-tests/test-cases/archive-weak/Makefile
new file mode 100644 (file)
index 0000000..676d1a4
--- /dev/null
@@ -0,0 +1,50 @@
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test if the linker already has a weak definition
+# it does not try to find another copy in an archive
+#
+# There are two case to test:
+# 1) both the main .o files and the archive have the same weak symbol (_foo)
+# 2) main.o has a weak symbol and the archive has a non-weak symbol (_baz)
+# In both cases the linker should ignore the archive. 
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} foo.c -c -o foo-${ARCH}.o 
+       ${CC} ${CCFLAGS} bar.c -c -o bar-${ARCH}.o 
+       ${CC} ${CCFLAGS} baz.c -c -o baz-${ARCH}.o 
+       libtool -static foo-${ARCH}.o  bar-${ARCH}.o  baz-${ARCH}.o -o libfoobar-${ARCH}.a
+       ${CC} ${CCFLAGS} main.c foo.c -lfoobar-${ARCH} -L. -o main-${ARCH} 
+       ${FAIL_IF_BAD_MACHO} main-${ARCH}
+       nm -m main-${ARCH} | grep _baz | grep weak | ${PASS_IFF_STDIN}
+
+clean:
+       rm -rf main-${ARCH} foo-${ARCH}.o bar-${ARCH}.o baz-${ARCH}.o libfoobar-${ARCH}.a
+       
+
diff --git a/unit-tests/test-cases/archive-weak/bar.c b/unit-tests/test-cases/archive-weak/bar.c
new file mode 100644 (file)
index 0000000..7fe6403
--- /dev/null
@@ -0,0 +1 @@
+int bar() { return 0; }
diff --git a/unit-tests/test-cases/archive-weak/baz.c b/unit-tests/test-cases/archive-weak/baz.c
new file mode 100644 (file)
index 0000000..387ccc1
--- /dev/null
@@ -0,0 +1,11 @@
+
+
+
+// intentionally not-weak
+int baz() 
+{ 
+       return 1; 
+}
+
+
+
diff --git a/unit-tests/test-cases/archive-weak/foo.c b/unit-tests/test-cases/archive-weak/foo.c
new file mode 100644 (file)
index 0000000..d7003fa
--- /dev/null
@@ -0,0 +1,13 @@
+
+
+void collisionChecker()  { }
+
+
+int __attribute__((weak)) foo() 
+{ 
+       collisionChecker();
+       return 1; 
+}
+
+
+
diff --git a/unit-tests/test-cases/archive-weak/main.c b/unit-tests/test-cases/archive-weak/main.c
new file mode 100644 (file)
index 0000000..d1ce4a9
--- /dev/null
@@ -0,0 +1,42 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+extern int foo();
+extern int bar();
+
+// intentionally weak 
+int __attribute__((weak)) baz() 
+{ 
+       return 1; 
+}
+
+int main()
+{
+       fprintf(stdout, "hello\n");
+       return foo() + bar() + baz();
+}
+
+
+
diff --git a/unit-tests/test-cases/auto-arch/Makefile b/unit-tests/test-cases/auto-arch/Makefile
new file mode 100644 (file)
index 0000000..e5caa64
--- /dev/null
@@ -0,0 +1,45 @@
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+#
+# The point of this test is a check that ld
+# can figure out which architecture is needed 
+# by looking at the .o files when -arch is not used.
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} hello.c -c -o hello.o  -mmacosx-version-min=10.4
+       ${LD} -lcrt1.o hello.o -o hello -lSystem 2> fail.log
+       ${FAIL_IF_BAD_MACHO} hello
+       file hello | grep ${ARCH} | ${PASS_IFF_STDIN}
+
+clean:
+       rm  hello.o hello fail.log
+       
+
diff --git a/unit-tests/test-cases/auto-arch/hello.c b/unit-tests/test-cases/auto-arch/hello.c
new file mode 100644 (file)
index 0000000..14d9363
--- /dev/null
@@ -0,0 +1,29 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+int main()
+{
+       fprintf(stdout, "hello\n");
+}
diff --git a/unit-tests/test-cases/blank-stubs/Makefile b/unit-tests/test-cases/blank-stubs/Makefile
new file mode 100644 (file)
index 0000000..514fd8b
--- /dev/null
@@ -0,0 +1,47 @@
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+ALL_ARCH_OPTIONS = $(patsubst %,-arch %,$(VALID_ARCHS))
+
+#
+# Test that blank stubs are handled properly
+#
+
+run: all
+
+all:
+# build example fully fat dylib
+       ${CC} `echo ${ALL_ARCH_OPTIONS}` -dynamiclib foo.c -o libfoo.dylib -install_name libfoo.dylib
+       lipo libfoo.dylib -remove ${ARCH} -output libfoo.dylib
+       lipo -create libfoo.dylib -arch_blank ${ARCH} -output libfoo.dylib
+       ${CC} ${CCFLAGS} main.c libfoo.dylib -o main
+       ${OTOOL} -L main | grep libfoo | ${FAIL_IF_STDIN}
+       ${PASS_IFF_GOOD_MACHO} main
+       
+
+clean:
+       rm -rf libfoo.dylib main
+       
\ No newline at end of file
diff --git a/unit-tests/test-cases/blank-stubs/foo.c b/unit-tests/test-cases/blank-stubs/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/blank-stubs/main.c b/unit-tests/test-cases/blank-stubs/main.c
new file mode 100644 (file)
index 0000000..6c9f6a4
--- /dev/null
@@ -0,0 +1,5 @@
+
+int main (void)
+{
+   return 0;
+}
diff --git a/unit-tests/test-cases/dwarf-debug-notes/Makefile b/unit-tests/test-cases/dwarf-debug-notes/Makefile
new file mode 100644 (file)
index 0000000..8b94b2f
--- /dev/null
@@ -0,0 +1,54 @@
+##
+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is a sanity check that ld
+# produces good "debug notes" stabs from dwarf .o files
+# Running nm through stabs-filter.pl produces connonical stabs
+# that can be diffed against a checked in know good set of stabs
+#
+
+run: all
+
+all: hello.o other.o crt1.o 
+       ${CXX} ${CCXXFLAGS} -gdwarf-2 hello.o other.o -o dwarf-hello-${ARCH} -L.
+       ${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 hello.o -mdynamic-no-pic
+
+other.o : other.cxx
+       ${CXX} ${CCXXFLAGS} -gdwarf-2 other.cxx -c -o other.o -mdynamic-no-pic
+
+# don't want any stabs in crt1.o to effect output, so my private stripped copy
+crt1.o : /usr/lib/crt1.o
+       strip -S /usr/lib/crt1.o -o crt1.o
+
+clean:
+       rm -rf dwarf-hello-${ARCH}  hello.o  other.o crt1.o dwarf-hello-${ARCH}.stabs
+
+
diff --git a/unit-tests/test-cases/dwarf-debug-notes/expected-stabs b/unit-tests/test-cases/dwarf-debug-notes/expected-stabs
new file mode 100644 (file)
index 0000000..756776e
--- /dev/null
@@ -0,0 +1,27 @@
+0000    SO CWD
+0000    SO hello.cxx
+0001   OSO CWD/hello.o
+0000 BNSYM 
+0000   FUN _main
+0000   FUN 
+0000 ENSYM 
+0000 BNSYM 
+0000   FUN __Z3fooi
+0000   SOL header.h
+0000   FUN 
+0000 ENSYM 
+0000    SO 
+0000    SO CWD
+0000    SO other.cxx
+0001   OSO CWD/other.o
+0000 BNSYM 
+0000   FUN __Z3bari
+0000   FUN 
+0000 ENSYM 
+0000  GSYM _init
+0000 STSYM __ZZ3bariE8bar_init
+0000  GSYM _uninit
+0000 STSYM _sinit
+0000 STSYM _suninit
+0000 STSYM __ZZ3bariE10bar_uninit
+0000    SO 
diff --git a/unit-tests/test-cases/dwarf-debug-notes/header.h b/unit-tests/test-cases/dwarf-debug-notes/header.h
new file mode 100644 (file)
index 0000000..aa960dd
--- /dev/null
@@ -0,0 +1,8 @@
+
+
+inline int foo(int x) 
+{ 
+       return x + 10;
+}
+
+extern int bar(int x);
\ No newline at end of file
diff --git a/unit-tests/test-cases/dwarf-debug-notes/hello.cxx b/unit-tests/test-cases/dwarf-debug-notes/hello.cxx
new file mode 100644 (file)
index 0000000..0d508e1
--- /dev/null
@@ -0,0 +1,33 @@
+/* -*- 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@
+ */
+#include <stdio.h>
+
+#include "header.h"
+
+
+int main()
+{
+       foo(bar(3));
+       fprintf(stdout, "hello\n");
+}
\ No newline at end of file
diff --git a/unit-tests/test-cases/dwarf-debug-notes/other.cxx b/unit-tests/test-cases/dwarf-debug-notes/other.cxx
new file mode 100644 (file)
index 0000000..dc4feb4
--- /dev/null
@@ -0,0 +1,18 @@
+
+#include "header.h"
+
+int uninit;
+int init = 1;
+static int suninit;
+static int sinit=0;
+
+int bar(int x)
+{
+       static int bar_uninit;
+       static int bar_init=3;
+       bar_uninit = x;
+       return 20 + suninit + sinit +
+               bar_init + bar_uninit + foo(x);
+}
+
+
diff --git a/unit-tests/test-cases/dwarf-debug-notes/stabs-filter.pl b/unit-tests/test-cases/dwarf-debug-notes/stabs-filter.pl
new file mode 100755 (executable)
index 0000000..706fd12
--- /dev/null
@@ -0,0 +1,25 @@
+#!/usr/bin/perl
+
+use strict;
+use Cwd;
+
+my $dir = getcwd;
+#my $xxx = $ARGV[1];
+
+while(<>)
+{
+       # get stabs lines that match "NNNNNNN - xxx"
+    if(m/^([0-9a-f]+) - ([0-9a-f]+) (.*?)$/)
+    {
+               # replace any occurances of cwd path with $CWD
+               my $line = $3;
+        if($line =~ m/(.*?)$dir(.*?)$/)
+               {
+                       $line = $1 . "CWD" . $2;
+               }
+               
+               printf "$line\n";
+       }
+}
+
+
diff --git a/unit-tests/test-cases/dwarf-ignore/Makefile b/unit-tests/test-cases/dwarf-ignore/Makefile
new file mode 100644 (file)
index 0000000..773e572
--- /dev/null
@@ -0,0 +1,41 @@
+##
+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is a sanity check that ld
+# strips out the dwarf segment by default
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} -gdwarf-2 hello.c -o dwarf-hello-${ARCH}
+       ${FAIL_IF_BAD_MACHO} dwarf-hello-${ARCH}
+       size -l dwarf-hello-${ARCH} | grep __DWARF | ${PASS_IFF_EMPTY}
+
+clean:
+       rm -rf dwarf-hello-${ARCH} 
+       
+
diff --git a/unit-tests/test-cases/dwarf-ignore/hello.c b/unit-tests/test-cases/dwarf-ignore/hello.c
new file mode 100644 (file)
index 0000000..e2f0fe9
--- /dev/null
@@ -0,0 +1,29 @@
+/* -*- 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@
+ */
+#include <stdio.h>
+
+int main()
+{
+       fprintf(stdout, "hello\n");
+}
\ No newline at end of file
diff --git a/unit-tests/test-cases/dwarf-strip/Makefile b/unit-tests/test-cases/dwarf-strip/Makefile
new file mode 100644 (file)
index 0000000..916eff1
--- /dev/null
@@ -0,0 +1,41 @@
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is a sanity check that ld -S
+# produces no debug notes (stabs)
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} -gdwarf-2 hello.c -Wl,-S -o dwarf-hello-${ARCH} 
+       ${FAIL_IF_BAD_MACHO} dwarf-hello-${ARCH}
+       nm -ap dwarf-hello-${ARCH} | grep -e "-" | ${PASS_IFF_EMPTY}
+
+clean:
+       rm -rf dwarf-hello-${ARCH} 
+       
+
diff --git a/unit-tests/test-cases/dwarf-strip/hello.c b/unit-tests/test-cases/dwarf-strip/hello.c
new file mode 100644 (file)
index 0000000..ddca819
--- /dev/null
@@ -0,0 +1,29 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+int main()
+{
+       fprintf(stdout, "hello\n");
+}
\ No newline at end of file
diff --git a/unit-tests/test-cases/header-pad/Makefile b/unit-tests/test-cases/header-pad/Makefile
new file mode 100644 (file)
index 0000000..e4393cd
--- /dev/null
@@ -0,0 +1,40 @@
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# 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} hello.c -o hello-${ARCH} -Wl,-headerpad -Wl,0x3000
+       ${PASS_IFF_GOOD_MACHO} hello-${ARCH}
+
+clean:
+       rm  hello-${ARCH}
+       
+
diff --git a/unit-tests/test-cases/header-pad/hello.c b/unit-tests/test-cases/header-pad/hello.c
new file mode 100644 (file)
index 0000000..14d9363
--- /dev/null
@@ -0,0 +1,29 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+int main()
+{
+       fprintf(stdout, "hello\n");
+}
diff --git a/unit-tests/test-cases/hello-world/Makefile b/unit-tests/test-cases/hello-world/Makefile
new file mode 100644 (file)
index 0000000..5ce56cc
--- /dev/null
@@ -0,0 +1,40 @@
+##
+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# 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} hello.c -o hello-${ARCH}
+       ${PASS_IFF_GOOD_MACHO} hello-${ARCH}
+
+clean:
+       rm  hello-${ARCH}
+       
+
diff --git a/unit-tests/test-cases/hello-world/hello.c b/unit-tests/test-cases/hello-world/hello.c
new file mode 100644 (file)
index 0000000..e2f0fe9
--- /dev/null
@@ -0,0 +1,29 @@
+/* -*- 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@
+ */
+#include <stdio.h>
+
+int main()
+{
+       fprintf(stdout, "hello\n");
+}
\ No newline at end of file
diff --git a/unit-tests/test-cases/literals-coalesce-alignment/Makefile b/unit-tests/test-cases/literals-coalesce-alignment/Makefile
new file mode 100644 (file)
index 0000000..b27351b
--- /dev/null
@@ -0,0 +1,45 @@
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is to verify that when two cstrings
+# are coalesced that the one with greater alignment is used.
+#
+
+run: all
+
+all:
+       ${CC} ${ASMFLAGS} cstring-align-0.s -c -o cstring-align-0-${ARCH}.o
+       ${CC} ${ASMFLAGS} cstring-align-3.s -c -o cstring-align-3-${ARCH}.o
+       ${LD} -arch ${ARCH} -r cstring-align-0-${ARCH}.o cstring-align-3-${ARCH}.o -o cstring-r-${ARCH}.o
+       ${OBJECTDUMP} cstring-align-3-${ARCH}.o | grep 'align:' > align-3
+       ${OBJECTDUMP} cstring-r-${ARCH}.o | grep 'align:' > align-r
+       ${PASS_IFF} diff align-3  align-r
+
+clean:
+       rm -rf cstring-align-0-${ARCH}.o cstring-align-3-${ARCH}.o cstring-r-${ARCH}.o align-3 align-r
+               
+       
+
diff --git a/unit-tests/test-cases/literals-coalesce-alignment/cstring-align-0.s b/unit-tests/test-cases/literals-coalesce-alignment/cstring-align-0.s
new file mode 100644 (file)
index 0000000..0dacbad
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * 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@
+ */
+
+       
+       .cstring
+L21: .ascii "hello\0"
diff --git a/unit-tests/test-cases/literals-coalesce-alignment/cstring-align-3.s b/unit-tests/test-cases/literals-coalesce-alignment/cstring-align-3.s
new file mode 100644 (file)
index 0000000..d2661dc
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * 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@
+ */
+
+       .cstring
+       .align 3
+L21: .ascii "hello\0"
diff --git a/unit-tests/test-cases/literals-coalesce/Makefile b/unit-tests/test-cases/literals-coalesce/Makefile
new file mode 100644 (file)
index 0000000..80465f8
--- /dev/null
@@ -0,0 +1,43 @@
+##
+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is to verify that literals are uniqued.
+# After running ld -r all duplicates should be removed.
+#
+
+run: all
+
+all:
+       ${CC} ${ASMFLAGS} literals.s -c -o literals-${ARCH}.o
+       ${OBJECTDUMP} literals-${ARCH}.o | grep 'name:'| uniq -c | grep -v '^   [1|2]' | ${FAIL_IF_STDIN}
+       ${LD} -arch ${ARCH} -r literals-${ARCH}.o -o literals-r-${ARCH}.o
+       ${OBJECTDUMP} literals-r-${ARCH}.o | grep 'name:' | uniq -d | ${PASS_IFF_EMPTY}
+
+clean:
+       rm -rf literals-${ARCH}.o -o literals-r-${ARCH}.o
+               
+       
+
diff --git a/unit-tests/test-cases/literals-coalesce/literals.s b/unit-tests/test-cases/literals-coalesce/literals.s
new file mode 100644 (file)
index 0000000..b8d4354
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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@
+ */
+
+       .literal8
+       
+L1:    .long 12345678
+       .long 87654321
+       
+L2:    .long 12345678
+       .long 87654322
+       
+L3:    .long 22345678
+       .long 87654321
+       
+L4:    .long 12345678
+       .long 87654321
+       
+       .literal4       
+L11:.long 12345678
+L12:.long 12345679
+L13:.long 22345678
+L14:.long 12345678
+       
+       .cstring
+L21: .ascii "hello\0"
+L22: .ascii "hello,there\0"
+L23: .ascii "there\0"
+L24: .ascii "hello\0"
diff --git a/unit-tests/test-cases/multiple-entry-points/Makefile b/unit-tests/test-cases/multiple-entry-points/Makefile
new file mode 100644 (file)
index 0000000..0a8dee0
--- /dev/null
@@ -0,0 +1,47 @@
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is to verify a .o file can round-trip
+# through ld -r correctly.  The ObjectDump utility is used
+# dump a "canonical" textual representation of a .o file.
+# The before and after .o files are then diff'ed.
+# No differences means this test passes
+#
+
+run: all
+
+all:
+       ${CC} ${ASMFLAGS} test.s -c -o test.${ARCH}.o
+       ${LD} -arch ${ARCH} -r -keep_private_externs test.${ARCH}.o -o test-r.${ARCH}.o
+       ${OBJECTDUMP} -no_sort test.${ARCH}.o > test.${ARCH}.o.dump
+       ${OBJECTDUMP} -no_sort test-r.${ARCH}.o > test-r.${ARCH}.o.dump
+       ${PASS_IFF} diff test.${ARCH}.o.dump test-r.${ARCH}.o.dump
+
+clean:
+       rm -rf test.${ARCH}.o test-r.${ARCH}.o test.${ARCH}.o.dump test-r.${ARCH}.o.dump
+       
+       
+
diff --git a/unit-tests/test-cases/multiple-entry-points/test.s b/unit-tests/test-cases/multiple-entry-points/test.s
new file mode 100644 (file)
index 0000000..dc3b340
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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@
+ */
+
+
+       .text
+       .align 2
+       
+       .globl _foo
+       .globl _foo2
+       .globl _foo3
+_foo:
+_foo2:
+_foo3:
+               nop
+               
+               
+               
+_bar:
+               nop
+               
+               
+       .globl _xx
+       .globl __xx
+_xx:
+__xx:
+               nop
+               
+               
+_ok:
+               nop
+               
diff --git a/unit-tests/test-cases/no-uuid/Makefile b/unit-tests/test-cases/no-uuid/Makefile
new file mode 100644 (file)
index 0000000..223c8b8
--- /dev/null
@@ -0,0 +1,61 @@
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test the we set emit LC_UUID correctly
+#
+
+run: all
+
+all:
+
+# Test with dwarf-2
+       ${CC} ${CCFLAGS} foo.c -o foo-${ARCH} -gdwarf-2
+       ${FAIL_IF_BAD_MACHO} foo-${ARCH}
+       ${OTOOL} -hlv foo-${ARCH} | grep LC_UUID | ${FAIL_IF_EMPTY}
+       rm -f foo-${ARCH}
+
+# Test with stabs
+       ${CC} ${CCFLAGS} foo.c -o foo-${ARCH} -gfull
+       ${FAIL_IF_BAD_MACHO} foo-${ARCH}
+       ${OTOOL} -hlv foo-${ARCH} | grep LC_UUID | ${FAIL_IF_STDIN}
+
+# Test with two files one with UUID
+       ${CC} ${CCFLAGS} bar.c -c -gdwarf-2
+       ${LD} -arch ${ARCH} bar.o -r -o bar-${ARCH}.o -no_uuid
+       ${CC} ${CCFLAGS} foo.c -c -gdwarf-2
+       ${LD} -arch ${ARCH} foo.o -r -o foo-${ARCH}.o
+       ${CC} ${CCFLAGS} foo-${ARCH}.o bar-${ARCH}.o -o temp-${ARCH}
+       ${FAIL_IF_BAD_MACHO} temp-${ARCH}
+       ${OTOOL} -hlv temp-${ARCH} | grep LC_UUID | ${FAIL_IF_EMPTY}
+       rm -f foo.o bar.o foo-${ARCH}.o bar-${ARCH}.o temp-${ARCH}
+
+# Test with with the flag disabling uuid
+       ${CC} ${CCFLAGS} foo.c -o foo-${ARCH} -Wl,-no_uuid -gdwarf-2
+       ${FAIL_IF_BAD_MACHO} foo-${ARCH}
+       ${OTOOL} -hlv foo-${ARCH} | grep LC_UUID | ${PASS_IFF_EMPTY}
+
+clean:
+       rm -rf foo-${ARCH} bar-${ARCH}.dylib temp-${ARCH}.dylib
diff --git a/unit-tests/test-cases/no-uuid/bar.c b/unit-tests/test-cases/no-uuid/bar.c
new file mode 100644 (file)
index 0000000..cbefe0f
--- /dev/null
@@ -0,0 +1,4 @@
+int bar (void)
+{
+   return 1;
+}
diff --git a/unit-tests/test-cases/no-uuid/foo.c b/unit-tests/test-cases/no-uuid/foo.c
new file mode 100644 (file)
index 0000000..57ed6ba
--- /dev/null
@@ -0,0 +1,4 @@
+int main (void)
+{
+   return 0;
+}
diff --git a/unit-tests/test-cases/private-non-lazy/Makefile b/unit-tests/test-cases/private-non-lazy/Makefile
new file mode 100644 (file)
index 0000000..655631c
--- /dev/null
@@ -0,0 +1,47 @@
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is to check that a non-lazy-pointer
+# in foo.o to a private-extern symbol in bar.o will
+# properly survive ld -r
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} -c foo.c -o foo.o
+       ${CC} ${CCFLAGS} -c bar.c -o bar.o
+       ${LD} -r foo.o bar.o -o foobar.o -arch ${ARCH}
+       ${CC} ${CCFLAGS} hello.c foobar.o -o hello
+       ${FAIL_IF_BAD_MACHO} hello
+       ${LD} -r foo.o bar.o -o foobar2.o -arch ${ARCH} -keep_private_externs
+       ${CC} ${CCFLAGS} hello.c foobar2.o -o hello2
+       ${PASS_IFF_GOOD_MACHO} hello2
+
+clean:
+       rm  foo.o bar.o foobar.o hello foobar2.o hello2
+       
+
diff --git a/unit-tests/test-cases/private-non-lazy/bar.c b/unit-tests/test-cases/private-non-lazy/bar.c
new file mode 100644 (file)
index 0000000..601dc69
--- /dev/null
@@ -0,0 +1,3 @@
+
+int __attribute__((visibility("hidden"))) foo = 0;
+
diff --git a/unit-tests/test-cases/private-non-lazy/foo.c b/unit-tests/test-cases/private-non-lazy/foo.c
new file mode 100644 (file)
index 0000000..6816d0b
--- /dev/null
@@ -0,0 +1,7 @@
+
+
+extern int foo;
+
+int getfoo() { return foo; }
+
+
diff --git a/unit-tests/test-cases/private-non-lazy/hello.c b/unit-tests/test-cases/private-non-lazy/hello.c
new file mode 100644 (file)
index 0000000..20dccc4
--- /dev/null
@@ -0,0 +1,31 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+extern int getfoo();
+
+int main()
+{
+       return getfoo();
+}
diff --git a/unit-tests/test-cases/read-only-relocs/Makefile b/unit-tests/test-cases/read-only-relocs/Makefile
new file mode 100644 (file)
index 0000000..6cea9e2
--- /dev/null
@@ -0,0 +1,42 @@
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is a sanity check that ld
+# will fail to link a dylib compiled with -mdynamic-no-pic
+#
+
+
+SHELL = bash # use bash shell so we can redirect just stderr
+
+run: all
+
+all:
+       ${FAIL_IFF} ${CC} ${CCFLAGS} test.c -mdynamic-no-pic -dynamiclib -o test-${ARCH}.dylib 2> fail.log
+
+clean:
+       rm  test-${ARCH}.dylib fail.log
+       
+
diff --git a/unit-tests/test-cases/read-only-relocs/test.c b/unit-tests/test-cases/read-only-relocs/test.c
new file mode 100644 (file)
index 0000000..f5be7e3
--- /dev/null
@@ -0,0 +1,30 @@
+/* -*- 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@
+ */
+
+int a=0; 
+
+int foo(void) 
+{ 
+       return a; 
+}
diff --git a/unit-tests/test-cases/relocs-asm/Makefile b/unit-tests/test-cases/relocs-asm/Makefile
new file mode 100644 (file)
index 0000000..6c0eb7b
--- /dev/null
@@ -0,0 +1,47 @@
+##
+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is to verify a .o file can round-trip
+# through ld -r correctly.  The ObjectDump utility is used
+# dump a "canonical" textual representation of a .o file.
+# The before and after .o files are then diff'ed.
+# No differences means this test passes
+#
+
+run: all
+
+all:
+       ${CC} ${ASMFLAGS} relocs-asm.s -c -o relocs-asm.${ARCH}.o
+       ${LD} -arch ${ARCH} -r -keep_private_externs relocs-asm.${ARCH}.o -o relocs-asm-r.${ARCH}.o
+       ${OBJECTDUMP} -no_content relocs-asm.${ARCH}.o > relocs-asm.${ARCH}.o.dump
+       ${OBJECTDUMP} -no_content relocs-asm-r.${ARCH}.o > relocs-asm-r.${ARCH}.o.dump
+       ${PASS_IFF} diff relocs-asm.${ARCH}.o.dump relocs-asm-r.${ARCH}.o.dump
+
+clean:
+       rm -rf relocs-asm.${ARCH}.o relocs-asm-r.${ARCH}.o relocs-asm.${ARCH}.o.dump relocs-asm-r.${ARCH}.o.dump
+       
+       
+
diff --git a/unit-tests/test-cases/relocs-asm/relocs-asm.s b/unit-tests/test-cases/relocs-asm/relocs-asm.s
new file mode 100644 (file)
index 0000000..5a40e49
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * 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@
+ */
+
+#if __ppc__ || __ppc64__
+
+       .text
+       .align 2
+               
+       .globl _test_loads
+_test_loads:
+       stmw r30,-8(r1)
+       stwu r1,-48(r1)
+Lpicbase:
+
+       ; PIC load of a 
+       addis r2,r10,ha16(_a-Lpicbase)
+       lwz r2,lo16(_a-Lpicbase)(r2)
+
+       ; PIC load of c 
+       addis r2,r10,ha16(_c-Lpicbase)
+       lwz r2,lo16(_c-Lpicbase)(r2)
+
+       ; absolute load of a
+       lis r2,ha16(_a)
+       lwz r2,lo16(_a)(r2)
+
+       ; absolute load of c
+       lis r2,ha16(_c)
+       lwz r2,lo16(_c)(r2)
+
+       ; absolute load of external
+       lis r2,ha16(_ax)
+       lwz r2,lo16(_ax)(r2)
+
+       ; absolute lea of external
+       lis r2,hi16(_ax)
+       ori r2,r2,lo16(_ax)
+
+
+       ; PIC load of a + addend
+       addis r2,r10,ha16(_a+0x19000-Lpicbase)
+       lwz r2,lo16(_a+0x19000-Lpicbase)(r2)
+
+       ; absolute load of a + addend
+       lis r2,ha16(_a+0x19000)
+       lwz r2,lo16(_a+0x19000)(r2)
+
+       ; absolute load of external + addend
+       lis r2,ha16(_ax+0x19000)
+       lwz r2,lo16(_ax+0x19000)(r2)
+
+       ; absolute lea of external + addend
+       lis r2,hi16(_ax+0x19000)
+       ori r2,r2,lo16(_ax+0x19000)
+
+
+       ; PIC load of a + addend
+       addis r2,r10,ha16(_a+0x09000-Lpicbase)
+       lwz r2,lo16(_a+0x09000-Lpicbase)(r2)
+
+       ; absolute load of a + addend
+       lis r2,ha16(_a+0x09000)
+       lwz r2,lo16(_a+0x09000)(r2)
+
+       ; absolute load of external + addend
+       lis r2,ha16(_ax+0x09000)
+       lwz r2,lo16(_ax+0x09000)(r2)
+
+       ; absolute lea of external + addend
+       lis r2,hi16(_ax+0x09000)
+       ori r2,r2,lo16(_ax+0x09000)
+
+       blr
+
+
+_test_calls:
+       ; call internal
+       bl      _test_branches
+       
+       ; call internal + addend
+       bl      _test_branches+0x19000
+
+       ; call external
+       bl      _external
+       
+       ; call external + addend
+       bl      _external+0x19000
+       
+
+_test_branches:
+       ; call internal
+       bne     _test_calls
+       
+       ; call internal + addend
+       bne     _test_calls+16
+
+       ; call external
+       bne     _external
+       
+       ; call external + addend
+       bne     _external+16
+#endif
+
+
+
+#if __i386__
+       .text
+       .align 2
+       
+       .globl _test_loads
+_test_loads:
+       pushl   %ebp
+Lpicbase:
+
+       # PIC load of a 
+       movl    _a-Lpicbase(%ebx), %eax
+       
+       # absolute load of a
+       movl    _a, %eax
+
+       # absolute load of external
+       movl    _ax, %eax
+
+       # absolute lea of external
+       leal    _ax, %eax
+
+
+       # PIC load of a + addend
+       movl    _a-Lpicbase+0x19000(%ebx), %eax
+
+       # absolute load of a + addend
+       movl    _a+0x19000(%ebx), %eax
+
+       # absolute load of external + addend
+       movl    _ax+0x19000(%ebx), %eax
+
+       # absolute lea of external + addend
+       leal    _ax+0x1900, %eax
+
+       ret
+
+
+_test_calls:
+       # call internal
+       call    _test_branches
+       
+       # call internal + addend
+       call    _test_branches+0x19000
+
+       # call external
+       call    _external
+       
+       # call external + addend
+       call    _external+0x19000
+       
+
+_test_branches:
+       # call internal
+       jne     _test_calls
+       
+       # call internal + addend
+       jne     _test_calls+16
+
+       # call external
+       jne     _external
+       
+       # call external + addend
+       jne     _external+16
+#endif
+
+
+
+       # test that pointer-diff relocs are preserved
+       .text
+_test_diffs:
+       .align 2
+Llocal2:
+       .long 0
+       .long Llocal2-_test_branches
+#if __ppc64__
+       .quad Llocal2-_test_branches
+#endif
+
+
+       .data
+_a:    
+       .long   0
+
+_b:
+#if __ppc__ || __i386__
+       .long   _test_calls
+       .long   _test_calls+16
+       .long   _external
+       .long   _external+16
+#elif __ppc64__
+       .quad   _test_calls
+       .quad   _test_calls+16
+       .quad   _external
+       .quad   _external+16
+#endif
+
+       # test that reloc sizes are the same
+Llocal3:
+       .long   0
+       
+Llocal4:
+       .long 0
+       
+       .long Llocal4-Llocal3
+       
+Lfiller:
+       .space  0x9000
+_c:
+       .long   0
+
diff --git a/unit-tests/test-cases/relocs-c/Makefile b/unit-tests/test-cases/relocs-c/Makefile
new file mode 100644 (file)
index 0000000..b400705
--- /dev/null
@@ -0,0 +1,49 @@
+##
+# 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@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# The point of this test is to verify a .o file can round-trip
+# through ld -r correctly.  The ObjectDump utility is used
+# dump a "canonical" textual representation of a .o file.
+# The before and after .o files are then diff'ed.
+# No differences means this test passes
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} test.c -c -o test.${ARCH}.o
+       ${LD} -arch ${ARCH} -r -keep_private_externs test.${ARCH}.o -o test-r.${ARCH}.o
+       ${OBJECTDUMP} -no_content test.${ARCH}.o > test.${ARCH}.o.dump
+       grep "plus" test.${ARCH}.o.dump | ${FAIL_IF_STDIN}
+       ${OBJECTDUMP} -no_content test-r.${ARCH}.o > test-r.${ARCH}.o.dump
+       grep "plus" test-r.${ARCH}.o.dump | ${FAIL_IF_STDIN}
+       ${PASS_IFF} diff test.${ARCH}.o.dump test-r.${ARCH}.o.dump
+
+clean:
+       rm -rf test.${ARCH}.o test-r.${ARCH}.o test.${ARCH}.o.dump test-r.${ARCH}.o.dump
+       
+
diff --git a/unit-tests/test-cases/relocs-c/test.c b/unit-tests/test-cases/relocs-c/test.c
new file mode 100644 (file)
index 0000000..b877760
--- /dev/null
@@ -0,0 +1,76 @@
+/* -*- 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@
+ */
+
+static int foo;
+
+int __attribute__((visibility("hidden"))) foofoo;
+
+static int                                                                                     uninit_static;
+static int                                                                                     init_static = 1;
+               int __attribute__((visibility("hidden")))       uninit_hidden;
+               int __attribute__((visibility("hidden")))       init_hidden = 1;
+               int                                                                                     uninit_global;
+               int                                                                                     init_global = 1;
+extern int                                                                                     extern_global;
+extern int      __attribute__((visibility("hidden")))  extern_hidden;
+
+static int                                                                                     uninit_static_array[4];
+static int                                                                                     init_static_array[4] = {1,2,3,4};
+               int __attribute__((visibility("hidden")))       uninit_hidden_array[4];
+               int __attribute__((visibility("hidden")))       init_hidden_array[4] = {1,2,3,4};
+               int                                                                                     uninit_global_array[4];
+               int                                                                                     init_global_array[4] = {1,2,3,4};
+extern int                                                                                     extern_global_array[4];
+
+int test1() { return uninit_static; }
+int test2() { return init_static; }
+int test3() { return uninit_hidden; }
+int test4() { return init_hidden; }
+int test5() { return uninit_global; }
+int test6() { return init_global; }
+int test7() { return extern_global; }
+int test8() { return extern_hidden; }
+
+int test_array1() { return uninit_static_array[2]; }
+int test_array2() { return init_static_array[2]; }
+int test_array3() { return uninit_hidden_array[2]; }
+int test_array4() { return init_hidden_array[2]; }
+int test_array5() { return uninit_global_array[2]; }
+int test_array6() { return init_global_array[2]; }
+int test_array7() { return extern_global_array[2]; }
+
+static int foo2;
+int test9() { return foo2; }
+
+
+int* p_init_global = &init_global;
+void* p_test1 = (void*)&test1;
+unsigned char pad = 2;
+unsigned char pad2 = 3;         // this padding throws off alignment on compiler generated anonymous non-lazy pointers...
+
+int func() __attribute__((visibility("hidden")));
+int func() { return foo; }
+
+int func2() { return func() + 1; }
+
diff --git a/unit-tests/test-cases/relocs-literals/Makefile b/unit-tests/test-cases/relocs-literals/Makefile
new file mode 100644 (file)
index 0000000..6d45efd
--- /dev/null
@@ -0,0 +1,47 @@
+##
+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# The point of this test is to verify a .o file can round-trip
+# through ld -r correctly.  The ObjectDump utility is used
+# dump a "canonical" textual representation of a .o file.
+# The before and after .o files are then diff'ed.
+# No differences means this test passes
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} -Os -mdynamic-no-pic test.c -c -o test.${ARCH}.o
+       ${LD} -arch ${ARCH} -r -keep_private_externs test.${ARCH}.o -o test-r.${ARCH}.o
+       ${OBJECTDUMP} -no_content test.${ARCH}.o > test.${ARCH}.o.dump
+       ${OBJECTDUMP} -no_content test-r.${ARCH}.o > test-r.${ARCH}.o.dump
+       ${PASS_IFF} diff test.${ARCH}.o.dump test-r.${ARCH}.o.dump
+
+clean:
+       rm -rf test.${ARCH}.o test-r.${ARCH}.o test.${ARCH}.o.dump test-r.${ARCH}.o.dump
+       
+
diff --git a/unit-tests/test-cases/relocs-literals/test.c b/unit-tests/test-cases/relocs-literals/test.c
new file mode 100644 (file)
index 0000000..31e87c2
--- /dev/null
@@ -0,0 +1,47 @@
+/* -*- 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@
+ */
+
+const char*                    foo = "foo";
+const char* const      bar = "bar";
+
+const char charArray1[] = "charArray1";
+static const char charArray2[] = "charArray2";
+
+
+const char* getString() { return "string"; }
+const char* getString2() { return charArray2; }
+const char* getString3() { return charArray1; }
+const char* getString4() { return foo; }
+
+
+float          f1 = 3.0;
+double         d1 = 3.0;
+long double ld1 = 3.0;
+
+
+
+float getSingle() { return 1.0; }
+double getDouble() { return 2.0; }
+long double getLongDouble() { return 3.0; }
+
diff --git a/unit-tests/test-cases/relocs-objc/Makefile b/unit-tests/test-cases/relocs-objc/Makefile
new file mode 100644 (file)
index 0000000..9b55f25
--- /dev/null
@@ -0,0 +1,47 @@
+##
+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# The point of this test is to verify a .o file can round-trip
+# through ld -r correctly.  The ObjectDump utility is used
+# dump a "canonical" textual representation of a .o file.
+# The before and after .o files are then diff'ed.
+# No differences means this test passes
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} test.m -c -o test.${ARCH}.o
+       ${LD} -arch ${ARCH} -r -keep_private_externs test.${ARCH}.o -o test-r.${ARCH}.o
+       ${OBJECTDUMP} -no_content test.${ARCH}.o > test.${ARCH}.o.dump
+       ${OBJECTDUMP} -no_content test-r.${ARCH}.o > test-r.${ARCH}.o.dump
+       ${PASS_IFF} diff test.${ARCH}.o.dump test-r.${ARCH}.o.dump
+
+clean:
+       rm -rf test.${ARCH}.o test-r.${ARCH}.o test.${ARCH}.o.dump test-r.${ARCH}.o.dump
+       
+
diff --git a/unit-tests/test-cases/relocs-objc/test.m b/unit-tests/test-cases/relocs-objc/test.m
new file mode 100644 (file)
index 0000000..a691e4a
--- /dev/null
@@ -0,0 +1,50 @@
+/* -*- 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@
+ */
+#include <Foundation/Foundation.h>
+
+
+@interface Foo : NSObject
+{
+       int ivar;
+}
+- (id) init;
+- (void) foo;
+@end
+
+
+@implementation Foo
+
+- (id) init
+{
+       self = [super init];
+       return self;
+}
+
+- (void) foo
+{
+       [self class];
+}
+
+@end
+
diff --git a/unit-tests/test-cases/stabs-coalesce/Makefile b/unit-tests/test-cases/stabs-coalesce/Makefile
new file mode 100644 (file)
index 0000000..c3414e0
--- /dev/null
@@ -0,0 +1,52 @@
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is a sanity check that ld
+# removes the stabs associated with a copy of a coalesced 
+# function that was removed.
+# Running nm through stabs-filter.pl produces connonical stabs
+# that can be diffed against a checked in know good set of stabs
+#
+
+run: all
+
+all: hello.o other.o 
+       ${CXX} ${CCXXFLAGS} -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} -gused hello.cxx -c -o hello.o
+
+other.o : other.cxx
+       ${CXX} ${CCXXFLAGS} -gused other.cxx -c -o other.o
+
+clean:
+       rm -rf stabs-hello-${ARCH}  hello.o other.o stabs-hello-${ARCH}.stabs stabs-hello-foo-count one
+
+
diff --git a/unit-tests/test-cases/stabs-coalesce/header.h b/unit-tests/test-cases/stabs-coalesce/header.h
new file mode 100644 (file)
index 0000000..378308f
--- /dev/null
@@ -0,0 +1,31 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+inline int foo(int x) 
+{ 
+       return x + 10;
+}
+
+extern int bar(int x);
diff --git a/unit-tests/test-cases/stabs-coalesce/hello.cxx b/unit-tests/test-cases/stabs-coalesce/hello.cxx
new file mode 100644 (file)
index 0000000..33bf273
--- /dev/null
@@ -0,0 +1,33 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+#include "header.h"
+
+
+int main()
+{
+       foo(bar(3));
+       fprintf(stdout, "hello\n");
+}
\ No newline at end of file
diff --git a/unit-tests/test-cases/stabs-coalesce/other.cxx b/unit-tests/test-cases/stabs-coalesce/other.cxx
new file mode 100644 (file)
index 0000000..ee97d7d
--- /dev/null
@@ -0,0 +1,41 @@
+/* -*- 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 "header.h"
+
+int uninit;
+int init = 1;
+static int suninit;
+static int sinit=0;
+
+int bar(int x)
+{
+       static int bar_uninit;
+       static int bar_init=3;
+       bar_uninit = x;
+       return 20 + suninit + sinit +
+               bar_init + bar_uninit + foo(x);
+}
+
+
diff --git a/unit-tests/test-cases/static-executable/Makefile b/unit-tests/test-cases/static-executable/Makefile
new file mode 100644 (file)
index 0000000..cee5f44
--- /dev/null
@@ -0,0 +1,40 @@
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is a sanity check that ld
+# can link a static executable (requires non-public archives)
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} test.c -static -o test-${ARCH} -L/usr/local/lib/system -lc_static -lm_static
+       ${PASS_IFF_GOOD_MACHO} test-${ARCH}
+
+clean:
+       rm  test-${ARCH}
+       
+
diff --git a/unit-tests/test-cases/static-executable/test.c b/unit-tests/test-cases/static-executable/test.c
new file mode 100644 (file)
index 0000000..ab472fb
--- /dev/null
@@ -0,0 +1,28 @@
+/* -*- 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@
+ */
+
+int main()
+{
+       return 0;
+}
diff --git a/unit-tests/test-cases/weak_import/Makefile b/unit-tests/test-cases/weak_import/Makefile
new file mode 100644 (file)
index 0000000..69ff397
--- /dev/null
@@ -0,0 +1,56 @@
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Test the weak_import attribute works
+#
+
+
+run: all
+
+all:   
+       ${CC} ${CCFLAGS} -dynamiclib -single_module foo.c -o libfoo-${ARCH}.dylib 
+       ${CC} ${CCFLAGS} -mmacosx-version-min=10.4 main.c -o main-${ARCH} libfoo-${ARCH}.dylib 
+       nm -m main-${ARCH} | grep _func1 | grep -v weak    >/dev/null
+       nm -m main-${ARCH} | grep _func2 | grep    weak    >/dev/null
+       nm -m main-${ARCH} | grep _func3 | grep -v weak    >/dev/null 
+       nm -m main-${ARCH} | grep _func4 | grep    weak    >/dev/null
+       nm -m main-${ARCH} | grep _data1 | grep -v weak    >/dev/null
+       nm -m main-${ARCH} | grep _data2 | grep    weak    >/dev/null
+       nm -m main-${ARCH} | grep _data3 | grep -v weak    >/dev/null
+       nm -m main-${ARCH} | grep _data4 | grep    weak    >/dev/null
+       ${CC} ${CCFLAGS} -mmacosx-version-min=10.4 main.c -dynamiclib -o main-${ARCH}.dylib libfoo-${ARCH}.dylib 
+       nm -m main-${ARCH}.dylib | grep _func1 | grep -v weak    >/dev/null
+       nm -m main-${ARCH}.dylib | grep _func2 | grep    weak    >/dev/null
+       nm -m main-${ARCH}.dylib | grep _func3 | grep -v weak    >/dev/null 
+       nm -m main-${ARCH}.dylib | grep _func4 | grep    weak    >/dev/null
+       nm -m main-${ARCH}.dylib | grep _data1 | grep -v weak    >/dev/null
+       nm -m main-${ARCH}.dylib | grep _data2 | grep    weak    >/dev/null
+       nm -m main-${ARCH}.dylib | grep _data3 | grep -v weak    >/dev/null
+       nm -m main-${ARCH}.dylib | grep _data4 | grep    weak    >/dev/null
+       ${PASS_IFF_GOOD_MACHO} main-${ARCH}.dylib
+       
+clean:
+       rm -rf libfoo-${ARCH}.dylib  main-${ARCH}  main-${ARCH}.dylib
diff --git a/unit-tests/test-cases/weak_import/foo.c b/unit-tests/test-cases/weak_import/foo.c
new file mode 100644 (file)
index 0000000..900b052
--- /dev/null
@@ -0,0 +1,17 @@
+
+
+#include "foo.h"
+
+void func1() {}
+void func2() {}
+void func3() {}
+void func4() {}
+
+
+int data1 = 0;
+int data2 = 0; // weak_import initialized
+int data3;
+int data4;             // weak_import uninitialized
+int data5 = 0;
+int data6 = 0; // weak_import 
+
diff --git a/unit-tests/test-cases/weak_import/foo.h b/unit-tests/test-cases/weak_import/foo.h
new file mode 100644 (file)
index 0000000..f455515
--- /dev/null
@@ -0,0 +1,16 @@
+
+
+extern void func1();
+extern void func2() __attribute__((weak_import));
+extern void func3();
+extern void func4() __attribute__((weak_import));
+
+extern int data1;
+extern int data2 __attribute__((weak_import));
+extern int data3;
+extern int data4 __attribute__((weak_import));
+extern int data5;
+extern int data6 __attribute__((weak_import));
+
+
+
diff --git a/unit-tests/test-cases/weak_import/main.c b/unit-tests/test-cases/weak_import/main.c
new file mode 100644 (file)
index 0000000..3266aed
--- /dev/null
@@ -0,0 +1,20 @@
+
+#include "foo.h"
+
+
+int* pdata5 = &data5;
+int* pdata6 = &data6;
+
+
+int main (void)
+{
+       // make non-lazy reference to func3 and func4
+       if ( &func3 == &func4 ) {
+               // make lazy reference to func3 and func4
+               func1();
+               func2();
+       }
+   
+   return data1 + data2 + data3 + data4;
+}
+
diff --git a/unit-tests/test-cases/zero-fill/Makefile b/unit-tests/test-cases/zero-fill/Makefile
new file mode 100644 (file)
index 0000000..a5f2f12
--- /dev/null
@@ -0,0 +1,40 @@
+##
+# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# The point of this test is a sanity check that ld
+# can link a program with a large zero-fill section
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} test.c -o test-${ARCH}
+       ${PASS_IFF_GOOD_MACHO} test-${ARCH}
+
+clean:
+       rm  test-${ARCH}
+       
+
diff --git a/unit-tests/test-cases/zero-fill/test.c b/unit-tests/test-cases/zero-fill/test.c
new file mode 100644 (file)
index 0000000..cfdc08c
--- /dev/null
@@ -0,0 +1,51 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+// if we used one big array, the linker would page align it
+// but we want to test a non-page align big chunk of zero-fill data
+int bigarray1[256];
+int bigarray2[256];
+int bigarray3[256];
+int bigarray4[256];
+int bigarray5[256];
+int bigarray6[256];
+static int staticbigarray1[256];
+static int staticbigarray2[256];
+static int staticbigarray3[256];
+static int staticbigarray4[256];
+static int staticbigarray5[256];
+static int staticbigarray6[256];
+
+int main()
+{
+       staticbigarray1[10] = 4;
+       staticbigarray2[10] = 4;
+       staticbigarray3[10] = 4;
+       staticbigarray4[10] = 4;
+       staticbigarray5[10] = 4;
+       staticbigarray6[10] = 4;
+       return 0;
+}
+