]> git.saurik.com Git - apple/ld64.git/commitdiff
ld64-59.2.tar.gz developer-tools-24 v59.2
authorApple <opensource@apple.com>
Wed, 6 Sep 2006 20:50:50 +0000 (20:50 +0000)
committerApple <opensource@apple.com>
Wed, 6 Sep 2006 20:50:50 +0000 (20:50 +0000)
48 files changed:
ChangeLog
doc/man/man1/rebase.1 [new file with mode: 0644]
ld64.xcodeproj/project.pbxproj
src/Architectures.hpp
src/MachOFileAbstraction.hpp
src/MachOReaderArchive.hpp
src/MachOReaderDylib.hpp
src/MachOReaderRelocatable.hpp
src/MachOWriterExecutable.hpp
src/ObjectDump.cpp
src/ObjectFile.h
src/Options.cpp
src/Options.h
src/SectCreate.cpp
src/ld.cpp
src/machochecker.cpp
src/rebase.cpp [new file with mode: 0644]
unit-tests/include/common.makefile
unit-tests/run-all-unit-tests
unit-tests/test-cases/bundle_loader/Makefile [new file with mode: 0644]
unit-tests/test-cases/bundle_loader/bar.c [new file with mode: 0644]
unit-tests/test-cases/bundle_loader/bundle.c [new file with mode: 0644]
unit-tests/test-cases/bundle_loader/main.c [new file with mode: 0644]
unit-tests/test-cases/dead_strip/Makefile [new file with mode: 0644]
unit-tests/test-cases/dead_strip/deadwood.c [new file with mode: 0644]
unit-tests/test-cases/dead_strip/main.c [new file with mode: 0644]
unit-tests/test-cases/dead_strip/main.exp [new file with mode: 0644]
unit-tests/test-cases/dwarf-debug-notes-r/Makefile [new file with mode: 0644]
unit-tests/test-cases/dwarf-debug-notes-r/bar.cxx [new file with mode: 0644]
unit-tests/test-cases/dwarf-debug-notes-r/expected-stabs [new file with mode: 0644]
unit-tests/test-cases/dwarf-debug-notes-r/foo.cxx [new file with mode: 0644]
unit-tests/test-cases/dwarf-debug-notes-r/main.cxx [new file with mode: 0644]
unit-tests/test-cases/dwarf-debug-notes-r/stabs-filter.pl [new file with mode: 0755]
unit-tests/test-cases/dwarf-debug-notes/expected-stabs
unit-tests/test-cases/filelist/Makefile [new file with mode: 0644]
unit-tests/test-cases/filelist/hello.c [new file with mode: 0644]
unit-tests/test-cases/late-link-error/Makefile [new file with mode: 0644]
unit-tests/test-cases/late-link-error/link_error.s [new file with mode: 0644]
unit-tests/test-cases/multiple-entry-points/test.s
unit-tests/test-cases/objc-references/Makefile [new file with mode: 0644]
unit-tests/test-cases/objc-references/test.m [new file with mode: 0644]
unit-tests/test-cases/rebase-basic/Makefile [new file with mode: 0644]
unit-tests/test-cases/rebase-basic/bar.m [new file with mode: 0644]
unit-tests/test-cases/rebase-basic/foo.c [new file with mode: 0644]
unit-tests/test-cases/relocs-asm/relocs-asm.s
unit-tests/test-cases/relocs-c/Makefile
unit-tests/test-cases/tentative-to-real/Makefile [new file with mode: 0644]
unit-tests/test-cases/tentative-to-real/test.c [new file with mode: 0644]

index d028e47a85dd665d45520a003394a59e03f519f3..26a83cedf341d9b8aca72e72106f25c77912ba7d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
 
------ Tagged ld64-47
-
+----- Tagged ld64-59
 
------ Tagged ld64-46
-
-2006-03-10     Nick Kledzik    <kledzik@apple.com>
+2006-06-22      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
+       <rdar://problem/4596726> ld64 lost DWARF debug notes
+       MachOReaderRelocatable.hpp: add fHasUUID so kDebugInfoStabsUUID can be set later
+       unit-tests/test-cases/dwarf-debug-notes-r: added test case
        
-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
+2006-06-21      Nick Kledzik    <kledzik@apple.com>
 
+       <rdar://problem/4567995> python 64-bit address miscalculation
+       src/MachOReaderRelocatable.hpp: change getTargetOffset() to sign extend the 32-bit value to 64-bits
        
------ 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-06-21      Nick Kledzik    <kledzik@apple.com>
 
-2006-02-24     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/4535036> ld64 seems to offset things incorrectly when using -r
+       src/MachOWriterExecutable.hpp: in -r mode, virtual sections don't increment address
 
-       * src/Options.cpp: <rdar://problem/4457078> 9A110: ld64 can't deal with section names >16 chars
 
-2006-02-23     Nick Kledzik    <kledzik@apple.com>
+----- Tagged ld64-58
 
-       * 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-06-16      Nick Kledzik    <kledzik@apple.com>
 
-2006-02-23     Nick Kledzik    <kledzik@apple.com>
+       src/rebase.cpp: fix page alignment problem
+       src/rebase.cpp: fix endianess problem with local non-lazy pointers
 
-       <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-06-15      Nick Kledzik    <kledzik@apple.com>
 
-2006-02-23     Nick Kledzik    <kledzik@apple.com>
+       src/rebase.cpp: fix to build in CurryWeed
+       ld64.xcodeproj/project.pbxproj: fix to build properly in CurryWeed 
 
-       <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-06-15      Nick Kledzik    <kledzik@apple.com>
 
-2006-02-22     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/4495309> Support .objc_class_name_* symbols     
+       src/ObjectFile.h: Add kSymbolTableInAsAbsolute
+       src/MachOReaderRelocatable.hpp: synthesize references to required objc classes
+       src/MachOWriterExecutable.hpp: write objc_class_name as absolute symbol
+       unit-tests/test-cases/objc-references: added
 
-       * src/Options.cpp: <rdar://problem/4453468> chnage printf on unknown arg to a throw
+2006-06-15      Nick Kledzik    <kledzik@apple.com>
 
------ Tagged ld64-39
+       <rdar://problem/4484369> SECTION_ATTRIBUTES unset in ppc64 mach-o header
+       src/MachOWriterExecutable.hpp: add section attribute for sections with code
 
-2006-02-20     Nick Kledzik    <kledzik@apple.com>
+2006-06-15      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
+       <rdar://problem/4569407> ld64 bogus duplicate symbol name linking GNU libobjc
+       src/MachOReaderRelocatable.hpp: only special case Apple's objc runtime objc classes
 
-2006-02-20     Nick Kledzik    <kledzik@apple.com>
+2006-06-15      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
+       <rdar://problem/4582999> x86_64: ".align" directive not honored
+       src/MachOReaderRelocatable.hpp: change code alignment to not depend on atom size
 
------ Tagged ld64-38
+2006-06-14      Nick Kledzik    <kledzik@apple.com>
 
-2006-02-17     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/4585335> jump table into middle of weak symbol causes error
+       src/MachOReaderRelocatable.hpp: create direct references to the interior of weak symbols
+       src/MachOWriterExecutable.hpp: don't error on absolute references to interior of weak symbols
 
-       * src/MachOWriterExecutable.hpp: <rdar://problem/4434578> set correct n_sect field of stabs
+2006-06-13      Nick Kledzik    <kledzik@apple.com>
 
-2006-02-15     Nick Kledzik    <kledzik@apple.com>
+       src/Options.cpp: allow -image_base as an alias for -seg1addr
 
-       * 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
+2006-06-13      Nick Kledzik    <kledzik@apple.com>
 
------ Tagged ld64-37
+       <rdar://problem/4585115> implement -d
+       src/Options.h: add fMakeTentativeDefinitionsReal
+       src/Options.cpp: set fMakeTentativeDefinitionsReal if -d option is found
+       src/MachOWriterExecutable.hpp: turn tentative into real definition if makeTentativeDefinitionsReal
+       unit-tests/test-cases/btentative-to-real: added test case
 
-2006-02-13  Eric Christopher  <echristo@apple.com>
+2006-06-13      Nick Kledzik    <kledzik@apple.com>
 
-       * src/MachOWriterExecutable.hpp (assignFileOffsets): Simplify. Add comments.
-       Adjust whitespace.
+       <rdar://problem/4584355> implement -bundle_loader
+       src/Options.h: add fBundleLoader bit to DynamicLibraryOptions
+       src/Options.cpp: handle -bundle_loader
+       src/ld.cpp: pass fBundleLoader bit to MachOReaderDylib
+       src/MachOReaderDylib.hpp: support reading MH_EXECUTE files if fBundleLoader is set
+       src/MachOWriterExecutable.hpp: set bundle loader ordinal as EXECUTABLE_ORDINAL
+       unit-tests/test-cases/bundle_loader: added test case
 
-2006-02-13     Nick Kledzik    <kledzik@apple.com>
+2006-06-12      Nick Kledzik    <kledzik@apple.com>
 
-       * src/MachOWriterExecutable.hpp: in Writer<x86>::fixUpReferenceRelocatable() fix kPCRel32 for external case
+       <rdar://problem/4583347> -syslibroot can cause "can't find ordinal for imported" error
+       src/MachOReaderDylib.hpp: in  Reader::reExports() compare install path in addition to load path
 
-2006-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-06-10      Nick Kledzik    <kledzik@apple.com>
 
-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
+       <rdar://problem/4548935> Need rebasing tool
+       src/rebase.cpp: added
+       unit-tests/test-cases/rebase-basic: added
+       doc/man/man1/rebase.1: added
+       ld64.xcodeproj/project.pbxproj:  added rebase target.  changed all targets to build with dwarf
+       
 
-2006-02-02     Nick Kledzik    <kledzik@apple.com>
+2006-06-10      Nick Kledzik    <kledzik@apple.com>
 
-       * src/MachOReaderRelocatable.hpp: properly coalesce 8-byte literals
-       * src/MachOWriterExecutable.hpp: support ppc64::kPointerDiff32
+       src/machochecker.cpp: add some ppc reloc sanity checking
 
------ Tagged ld64-32
+----- Tagged ld64-57
 
-2006-02-02     Nick Kledzik    <kledzik@apple.com>
+2006-06-06      Nick Kledzik    <kledzik@apple.com>
 
-       * src/MachOReaderRelocatable.hpp: support anonymous zero fill atoms
+       <rdar://problem/4565088> ld64 is not adding a final '/' char on the initial directory-name SO stab debug map entry
+       ld.cpp: Change Linker::synthesizeStabs() to assure directory SO always has a trailing slash
+       unit-tests/test-cases/dwarf-debug-notes/expected-stabs: update with trailing /
+       
+2006-06-06      Nick Kledzik    <kledzik@apple.com>
 
-2006-02-02     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/4572702> -sectcreate of a 0-byte section fails  
+       MachOWriterExecutable.cpp: Don't error out on zero length segments
+       MachOWriterExecutable.cpp: For ppc64 reloc base address is the first writable segment iff
+        there is a writable segment >4GB from base address
 
-       * 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-06-04  Eric Christopher  <echristo@apple.com>
 
-2006-02-01     Nick Kledzik    <kledzik@apple.com>
+       Radar 4560240
+       Radar 3964999
+       * src/ld.cpp (createReader): Fixed error message.
+       (resolve): Ditto.
+       (resolveFrom): Ditto.
+       (checkUndefines): Ditto.
 
-       * src/MachOReaderRelocatable.hpp: Support -macosx_version_min 10.5
+----- Tagged ld64-56
 
-2006-02-01     Nick Kledzik    <kledzik@apple.com>
+2006-05-23      Nick Kledzik    <kledzik@apple.com>
 
-       * src/MachOReaderRelocatable.hpp: don't try to parse debug_line dwarf if no symboled atoms
+       <rdar://problem/4558079> No debug notes for ObjC methods when linking with ld64
+       ld.cpp: don't limit debug notes to functions starting with underscore
 
------ Tagged ld64-31
+2006-05-22      Nick Kledzik    <kledzik@apple.com>
 
-2006-02-01  Eric Christopher  <echristo@apple.com>
+       <rdar://problem/4556982> ld64 spends much time in mach_o::relocatable::Reader<x86_64>::findAtomByName
+       * src/MachOReaderRelocatable.hpp: add makeReferenceToSymbol() so that x86_64 does not need to do by-name lookups
 
-       * 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-05-22      Nick Kledzik    <kledzik@apple.com>
 
+       <rdar://problem/4535044> remove inferring warning
+       * ld.cpp: Remove "inferring" warning.  If a link failed and now arch was specifed add which arch was
+       inferred to error message
 
-2006-01-31     Nick Kledzik    <kledzik@apple.com>
+2006-05-19      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
+       <rdar://problem/4544001> ld64 does not honor -arch_multiple
+       * ld.cpp: If fOptions.printArchPrefix(), add architecture name to error message
 
-2006-01-31     Nick Kledzik    <kledzik@apple.com>
+2006-05-19      Nick Kledzik    <kledzik@apple.com>
 
-       * ld64.xcodeproj/project.pbxproj : Make buildable on Leopard
-       * src/MachOFileAbstraction.hpp: make buildable without latest cctools headers
+       <rdar://problem/4555973> Support S_16BYTE_LITERALS section types
+       * src/MachOReaderRelocatable.hpp: support S_16BYTE_LITERALS
+       * src/MachOWriterExecutable.hpp: support S_16BYTE_LITERALS
 
-2006-01-31     Nick Kledzik    <kledzik@apple.com>
+2006-05-19      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
+       <rdar://problem/4548803> "warning can't parse dwarf compilation unit info" warnings building debug
+       * src/MachOReaderRelocatable.hpp: fix bugs in dwarf line table parsing
 
-2006-01-30  Eric Christopher  <echristo@apple.com>
+----- Tagged ld64-55
 
-       * src/ExecutableFile.h: Indent.
+2006-05-18      Nick Kledzik    <kledzik@apple.com>
 
-2006-01-30     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/4534339> Default the pagezero size to 4GB for x86-64
+       * src/Options.cpp: Chnage default the pagezero size to 4GB for x86-64
 
-       * src/MachOReaderRelocatable.hpp: performance improvements
-       * src/ld.cpp: now that stubs are synthesized in write, don't need to special case anymore
+2006-05-18      Nick Kledzik    <kledzik@apple.com>
 
-2006-01-30     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/4552825> x86_64 CarbonCore fails to link with "atom not found in symbolIndex"
+       * src/MachOWriterExecutable.hpp: in buildObjectFileFixups() don't call addObjectRelocs() on kNoFixUp references
 
-       * src/MachOReaderRelocatable.hpp: fix parsing of pcc relocs
-       * unit-tests/test-cases/relocs-asm/relocs-asm.s: add test case for above
+2006-05-18      Nick Kledzik    <kledzik@apple.com>
 
-2006-01-29     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/4553555> ld64: .section defaults to read-only
+       * src/MachOReaderRelocatable.hpp: default unknown segments to r/w
 
-       * 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-05-18      Nick Kledzik    <kledzik@apple.com>
 
-2006-01-29     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/4551990> -fvisibility=hidden causes crashes for x86_64
+       * src/MachOWriterExecutable.hpp: properly handle RIP relative tentative definitions
 
-       * src/Options.cpp: verify -allow_stack_execute is only used on main executables
+2006-05-12      Nick Kledzik    <kledzik@apple.com>
 
-2006-01-29     Nick Kledzik    <kledzik@apple.com>
+       * src/Architectures.hpp: add x86::kAbsolute32
+       * src/MachOReaderRelocatable.hpp: generate x86::kAbsolute32 for mdynamic-no-pic instructions
+       * src/MachOWriterExecutable.hpp: process x86::kAbsolute32 reference kind
 
-       * src/MachOReaderRelocatable.hpp: sync with latest dwarf reader from Geoff
-       * src/debugline.c: sync with latest dwarf reader from Geoff
+----- Tagged ld64-54
 
-2006-01-27  Eric Christopher  <echristo@apple.com>
+2006-05-11      Nick Kledzik    <kledzik@apple.com>
 
-       * src/ld.cpp (Linker::syntesizeStabs): Correct spelling. Update all uses.
+       <rdar://problem/4545108> CF-393 failes to link for x86_64
+       * src/MachOWriterExecutable.cpp: fix sign extension for Rel32 relocs in Writer<x86_64>::fixUpReferenceRelocatable
 
-2006-01-27  Eric Christopher  <echristo@apple.com>
+2006-05-11      Nick Kledzik    <kledzik@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.
+       <rdar://problem/4501434> warning arch x86_64 not found using i386
+       * src/ld.cpp: remove hack to allow x86_64 to link against i386 dylibs
 
-2006-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-05-10      Nick Kledzik    <kledzik@apple.com>
 
-2006-01-27  Eric Christopher  <echristo@apple.com>
+       <rdar://problem/4543754> x86_64: .objc_class_name symbol names scrambled
+       * src/MachOReaderRelocatable.hpp: properly compute alignment of __OBJC __class sections
 
-       * 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>
+2006-05-08      Nick Kledzik    <kledzik@apple.com>
 
-       * src/MachOWriterExecutable.hpp: handle NULL strings in SO debug notes
+       <rdar://problem/3894083> Support -dead_strip
+       * src/Options.h/cpp: implement -why_load and -why_live.  Enable -dead_strip.
+       * src/MachOReaderArchive.hpp: implement -why_load
+       * src/MachOReaderRelocatable.hpp: suppress GCC_except_table* symbols in final output
+       * src/ld.cpp: implement dead code stripping
+       * unit-tests/test-cases/dead_strip: added
 
-2006-01-26     Nick Kledzik    <kledzik@apple.com>
+----- Tagged ld64-53
 
-       * src/MachOWriterExecutable.hpp: fix header padding calculation and thread state
+2006-05-05      Nick Kledzik    <kledzik@apple.com>
 
-2006-01-26     Nick Kledzik    <kledzik@apple.com>
+       * src/Options.cpp: make 10.4 be minimum OS version for newer architectures
 
-       Rewrite all stabs processing.
-       Move sythesize of debug notes into ld.cpp
+2006-05-05      Nick Kledzik    <kledzik@apple.com>
 
-2006-01-26     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/4147604> N_SO symbols in 64-bit builds have a zero address for n.n_value
+       * src/ld.cpp: for SO stabs, associate first and last atom in the SO range
+       * src/MachOWriterExecutable.hpp: use atom associated with SO stab to set ins n_value
 
-       * src/MachOWriterExecutable.hpp: fix ppc and ppc64 stub relocs
+2006-05-05      Nick Kledzik    <kledzik@apple.com>
 
-2006-01-25     Nick Kledzik    <kledzik@apple.com>
+       * MachOWriterExecutable.hpp: fix end FUN stab to have length of function
 
-       * ld64.xcodeproj/project.pbxproj: special case building in Curry
 
-2006-01-25     Nick Kledzik    <kledzik@apple.com>
+2006-05-02      Nick Kledzik    <kledzik@apple.com>
 
-       * src/MachOWriterExecutable.hpp: fix bugs in stub/lazy-pointer synthesis
+       <rdar://problem/4496250> 64-bit main executables should have 4GB zero page by default
+       * src/Opptions.cpp: change default pagezero_size to 4GB for ppc64
+       <rdar://problem/4492850> 64 bit: apps with -mdynamic-no-pic seg fault when page zero > 4GB
+       * src/MachOWriterExecutable.cpp: rework pagezero for ppc64 so that if any mdynamic-no-pic code
+       is found, the code is kept in the low 2GB, and a new segment is create to map away up to 4GB.
 
-2006-01-24  Eric Christopher  <echristo@apple.com>
+2006-05-02      Nick Kledzik    <kledzik@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.
+       * src/Opptions.cpp: remove warning about -stack_addr not specified.  Add warning if 32-bit stack
+       overlaps shared region
 
-2006-01-24     Nick Kledzik    <kledzik@apple.com>
+----- Tagged ld64-52.1
 
-       * src/MachOReaderRelocatable.hpp: better C++ eh parsing
+2006-05-01      Nick Kledzik    <kledzik@apple.com>
 
-2006-01-23  Eric Christopher  <echristo@apple.com>
+       * src/MachOReaderRelocatable.cpp: rework handleAnonymousNonLazyPointers() to handle anl's in the middle
+       the __data section too.
 
-       * 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.
+----- Tagged ld64-52
 
-2006-01-23     Nick Kledzik    <kledzik@apple.com>
+2006-04-28      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
+       <rdar://problem/4513304> 64-bit: 9A152 TextEdit crashes in dlopen on bring-up
+       * src/MachOReaderRelocatable.cpp: rework anonymous non-lazy-pointer detection
 
-2006-01-23     Nick Kledzik    <kledzik@apple.com>
+2006-04-28      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
+       <rdar://problem/4528054> 64 Bit: Development build of ppc64 TextEdit gets confused about static variables
+       * src/MachOReaderRelocatable.cpp: mark non-lazy-pointer atoms as scopeTranslationUnit if targetting a static symbol
 
-2006-01-17     Nick Kledzik    <kledzik@apple.com>
 
-       * src/MachOReaderRelocatable.hpp: tweaks to synthesizing debug notes
+2006-04-27      Nick Kledzik    <kledzik@apple.com>
 
-2006-01-16     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/4498971> dyld crashes ungracefully on x86_64 when there is an internal exception
+       * src/MachOWriterExecutable.cpp: allow non-zero PCRELGOT addends (used by C++ eh frames)
 
-       * 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-04-21      Nick Kledzik    <kledzik@apple.com>
 
-2006-01-11     Nick Kledzik    <kledzik@apple.com>
+       * src/Options.cpp: fix default address for ppc64 custom stack
+       * src/MachOWriterExecutable.cpp: fix set up of ppc64 custom stack
 
-       * 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>
+2006-04-14      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
+       * src/Options.cpp: fix -sub_library processing to work it dylib is specifed with leaf name
 
-2006-01-10     Nick Kledzik    <kledzik@apple.com>
+----- Tagged ld64-51.1
 
-       * src/MachOReaderRelocatable.hpp: warn if dwarf can't be parsed
-       * src/MachOReaderArchive.hpp: modTime for OSO stabs from archives is .a modTime
+2006-04-13      Nick Kledzik    <kledzik@apple.com>
 
-2006-01-09     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/4513304> 64-bit: 9A152 TextEdit crashes in dlopen on bring-up
+       * src/MachOReaderRelocatable.hpp: when detecting anonymous non-lazy-pointers disqualify data
+       that points to static or global symbols
+       * src/ld.cpp: print version of ld64 in error messages
 
-       * track modification time of .o files so that sythesized OSO stab will have it
 
-2006-01-09     Nick Kledzik    <kledzik@apple.com>
+----- Tagged ld64-51
 
-       * src/MachOFileAbstraction.hpp: add macho_uuid_command
-       * src/MachOWriterExecutable.cpp: add UUID load command to generated files
+2006-04-11      Nick Kledzik    <kledzik@apple.com>
 
-2006-01-09     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/4499168> exported symbols not properly stripped
+       * src/MachOReaderRelocatable.hpp: enable AnonymousAtom::setScope()
 
-       * 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-03-31      Nick Kledzik    <kledzik@apple.com>
 
-2006-01-05     Nick Kledzik    <kledzik@apple.com>
+       <rdar://problem/4498391> ld64 fails when linking debug ppc64 HIToolbox
+       * src/MachOReaderRelocatable.hpp: handle anonymous non-lazy pointers encoded with local relocations
+       * src/MachOWriterExecutable.hpp: in -r mode, only generated INDIRECT_SYMBOL_LOCAL for non-lazy targets that
 
-       * src/MachOReaderRelocatable.hpp: support new relocations
 
-2006-01-05     Nick Kledzik    <kledzik@apple.com>
+2006-03-31      Nick Kledzik    <kledzik@apple.com>
 
-       * src/MachOReaderDylib.hpp: support MH_DYLIB_STUB
-       * src/MachOReaderRelocatable.hpp: Add Geoff's comp unit extractor
+       <rdar://problem/4496499> ld64 should remove generated file if link errors out
+       * src/MachOWriterExecutable.hpp: catch exceptions in Writer<A>::write(), delete output file, and rethrow
 
-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
+----- Tagged ld64-50
 
-2006-01-03  Eric Christopher  <echristo@apple.com>
+2006-03-29      Nick Kledzik    <kledzik@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.
+       * src/MachOWriterExecutable.hpp: fix x86_64 addends when -multi_module forces an external relocation
 
-2006-01-02     Nick Kledzik    <kledzik@apple.com>
+2006-03-29      Nick Kledzik    <kledzik@apple.com>
 
-       * Refactor: move Atom::writeContent() to Writer
+       * src/MachOReaderRelocatable.hpp: synthesize .objc_class_name symbols
+       * src/MachOFileAbstraction.hpp: use strncpy for sect/seg names to zero fill trailing space
 
-2005-12-23     Nick Kledzik    <kledzik@apple.com>
+2006-03-28      Nick Kledzik    <kledzik@apple.com>
 
-       * Reworked, simplify, and document test harness
-       * unit-tests/README: Added
+       * src/MachOReaderRelocatable.hpp: fix spurious warning about dwarf line info
 
-2005-12-23     Nick Kledzik    <kledzik@apple.com>
+----- Tagged ld64-49.1
 
-       * src/MachOReaderRelocatable.hpp: fixes for Objective-C
-       * unit-tests/test-cases/relocs-objc: Added
+2006-03-25      Nick Kledzik    <kledzik@apple.com>
 
-2005-12-22     Nick Kledzik    <kledzik@apple.com>
+       * MachOWriterExecutable.hpp : don't complain about ppc64 dyld being based > 4GB
 
-       * src/MachOReaderRelocatable.hpp: fix check that next reloc is pair
-       * src/MachOReaderRelocatable.hpp: Add code to synthesize essential stabs from dwarf
+----- Tagged ld64-49
 
-2005-12-21     Nick Kledzik    <kledzik@apple.com>
+2006-03-24     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
+       * src/MachOWriterExecutable.hpp: dyld is allowed to have synthesized non-lazy pointers
+       <rdar://problem/4488113> ld64 is after processing bad GSYM stabs
+       * src/MachOReaderRelocatable.hpp: if a GSYM is found that does not match any data symbol, suppress it
 
-2005-12-15  Eric Christopher  <echristo@apple.com>
+2006-03-23     Nick Kledzik    <kledzik@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/MachOWriterExecutable.hpp: in Writer<x86>::fixUpReferenceFinal() fix when x86::kPointer is for an
+       external relocation
 
-       * 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.
+2006-03-23     Nick Kledzik    <kledzik@apple.com>
 
-2005-12-15     Nick Kledzik    <kledzik@apple.com>
+       * src/Options.cpp: change macosx-min-version to default to a per-architecture setting
+         add warning if -pagezero_size is not page aligned
+       * src/MachOWriterExecutable.hpp: properly handle external relocations for ppc64 with 4GB pagezero
+       * src/machochecker.cpp: sanity check relocation records
 
-       * src/MachOReaderRelocatable.hpp: Add comments about dwarf
+----- Tagged ld64-48
 
-2005-12-14     Nick Kledzik    <kledzik@apple.com>
+2006-03-21     Nick Kledzik    <kledzik@apple.com>
 
-       * src/ELFFileAbstraction.hpp: Added
-       * src/ELFReaderRelocatable.hpp: Added
-       * Lot of fixes for new architecture
+       <rdar://problem/4481406> 64bit: passing function pointer to another function passes the wrong function address
+       * src/MachOReaderRelocatable.hpp: when processing a non-lazy pointer to a static function, don't accidentally
+       match it to a STAB symbol.
 
-2005-12-13     Nick Kledzik    <kledzik@apple.com>
+2006-03-21     Nick Kledzik    <kledzik@apple.com>
 
-       * src/MachOReaderRelocatable.hpp: check for S_ATTR_DEBUG and ignore those sections
-       * unit-tests/test-cases/dwarf-ignore: added
+       <rdar://problem/4180168> .eh symbols make up 13% of libstdc++'s stripped binary size
+       * src/ObjectFile.h: add ReaderOptions.fForFinalLinkedImage
+       * src/Options.cpp: setup ReaderOptions.fForFinalLinkedImage
+       * src/MachOReaderRelocatable.hpp: mark .eh symbols kSymbolTableNotIn when building final linked image
 
-2005-12-12     Nick Kledzik    <kledzik@apple.com>
+2006-03-21     Nick Kledzik    <kledzik@apple.com>
 
-       * Added test harness and three initial tests:
-               relocs-asm, relocs-c, and hello-world
+       <rdar://problem/4473742> ld64 does not parse optional second argument to -filelist
+       * unit-tests/test-cases/filelist: added
+       * src/Options.cpp: in Options::loadFileList() handle comma option
 
-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.
+----- Tagged ld64-47
 
-2005-12-12     Nick Kledzik    <kledzik@apple.com>
 
-       * src/ObjectDump.cpp: Add command line options: -no_content, -stabs, -no_sort
+----- Tagged ld64-46
 
-2005-12-11  Eric Christopher  <echristo@apple.com>
+2006-03-10     Nick Kledzik    <kledzik@apple.com>
 
-       * src/Options.cpp: Reformat.
-       * src/Options.h: Ditto.
+       <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
 
-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.
+2006-03-09     Nick Kledzik    <kledzik@apple.com>
 
-2005-12-06     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
 
-       * src/Options.cpp src/Options.h: Add design comments
+2006-03-09     Nick Kledzik    <kledzik@apple.com>
 
-2005-12-05  Eric Christopher  <echristo@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
 
-       * src/ld.cpp (Linker::createWriter): Uncomment ppc64 and
-       i386 linkers.
+2006-03-06     Nick Kledzik    <kledzik@apple.com>
 
-2005-12-05  Eric Christopher  <echristo@apple.com>
+       * src/Options.cpp: addSectionAlignment, warn if -sectalign alignment is not a power of two
 
-       * ChangeLog: New file.
+----- Tagged ld64-45
 
-2005-12-02     Nick Kledzik    <kledzik@apple.com>
+2006-03-06     Nick Kledzik    <kledzik@apple.com>
 
-       * src/ObjectFile.h: Add design comments
+       <rdar://problem/4466930> <rdar://problem/4467982> ld64 failed: rel32 out of range when linking a dylib
+       * src/MachOWriterExecutable.cpp: in  Writer<x86_64>::fixUpReferenceFinal add (int32_t) cast
 
-2005-11-28     Nick Kledzik    <kledzik@apple.com>
+2006-03-06     Nick Kledzik    <kledzik@apple.com>
 
-       * Refactor Atom to use getDefinitionKind()
+       <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
 
-2005-11-21     Nick Kledzik    <kledzik@apple.com>
+2006-03-06     Nick Kledzik    <kledzik@apple.com>
 
-       * src/MachOWriterExecutable.hpp: don't generate section for commons in -r mode
+       <rdar://problem/4457818> x86_THREAD_STATE64_COUNT will change, ld64 must adapt
+       * src/MachOWriterExecutable.hpp: update ThreadsLoadCommandsAtom<x86_64> for new thread status layout
 
-2005-11-18     Nick Kledzik    <kledzik@apple.com>
+----- Tagged ld64-44
 
-       * x86 tweaks
+2006-03-04     Nick Kledzik    <kledzik@apple.com>
 
-2005-11-18     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.
 
-       * src/ObjectDump.cpp: make work with command line arguments
+2006-03-02     Nick Kledzik    <kledzik@apple.com>
 
-2005-11-18     Nick Kledzik    <kledzik@apple.com>
+       * src/ld.cpp: only re-map page aligned sub-parts of a fat file.  A conformat mmap() requires alignment.
 
-       * Massive rework to remove preprocessor conditionals and use templates
+----- Tagged ld64-43
 
-2005-11-14     Nick Kledzik    <kledzik@apple.com>
+2006-03-03     Nick Kledzik    <kledzik@apple.com>
 
-       * Created new Subversion repository for ld64 from cvs tag ld64-27.2
+       <rdar://problem/4465443> RIP-relative offsets aren't handled properly when the instruction has immediate operands
+       * src/Architectures.hpp: add x86_64::kPCRel32_*
+       * src/MachOReaderRelocatable.hpp: generate x86_64::kPCRel32_*
+       * src/MachOWriterExecutable.hpp: process x86_64::kPCRel32_*
diff --git a/doc/man/man1/rebase.1 b/doc/man/man1/rebase.1
new file mode 100644 (file)
index 0000000..6743a96
--- /dev/null
@@ -0,0 +1,39 @@
+.Dd June 6, 2006
+.Dt rebase 1
+.Os Darwin
+.Sh NAME
+.Nm rebase
+.Nd "Changes base address of dylibs and bundles"
+.Sh SYNOPSIS
+.Nm
+.Op Fl low_address Ar addr 
+.Op Fl high_address Ar addr 
+.Op Fl arch Ar arch 
+.Op Fl v
+.Ar file(s)
+.Sh DESCRIPTION
+The base address of an image (dylib or bundle) is the preferred address for it to be loaded.  By
+default all images are built with a base address of zero.  At runtime, if the
+preferred memory range is already occupied, dyld will "slide" the image to a new address range.
+There is a small cost to the slide, as dyld must do some fix ups.
+The rebase tool takes a list of images and adjust their base address to be non-overlapping. If no
+low or high address is specified, the a suitable address range is choosen for the architecture.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl low_address Ar addr
+Force the base address for the first image to be 
+.Ar addr
+(specified in hex). Each subsequent file gets the next available base address.
+.It Fl high_address Ar addr
+Force the base address for the last image to be such that when that image is loaded it occupies 
+memory up to
+.Ar addr
+(specified in hex). Each preceeding file gets the previous available base address.
+.It Fl arch Ar arch
+Only rebase the specified architecture.  Other architectures in a universal image are left as is.
+.It Fl v
+Verbose. Print information about rebasing done.
+.El
+.Sh SEE ALSO
+.Xr ld 1
index 1ce18dd24877db4ad003650a380641357b7a029c..3475042ebe539c968378c74763866ce23f44a82e 100644 (file)
                        buildPhases = (
                                F96D5367094A2754008E9EE8 /* ShellScript */,
                        );
-                       buildSettings = {
-                               PRODUCT_NAME = "unit-tests";
-                       };
                        dependencies = (
                                F96D536A094A275D008E9EE8 /* PBXTargetDependency */,
                                F96D536C094A275F008E9EE8 /* PBXTargetDependency */,
+                               F96904890A4333AC00B77D2A /* PBXTargetDependency */,
                                F9EA73970974999B008B4F1D /* PBXTargetDependency */,
                        );
                        name = "unit-tests";
                        productName = "unit-tests";
                };
+               F9B1A2670A3A567B00DA8FAB /* all */ = {
+                       isa = PBXAggregateTarget;
+                       buildConfigurationList = F9B1A26C0A3A568700DA8FAB /* Build configuration list for PBXAggregateTarget "all" */;
+                       buildPhases = (
+                       );
+                       dependencies = (
+                               F9B1A2690A3A568200DA8FAB /* PBXTargetDependency */,
+                               F9B1A26B0A3A568400DA8FAB /* PBXTargetDependency */,
+                       );
+                       name = all;
+                       productName = all;
+               };
 /* End PBXAggregateTarget section */
 
 /* Begin PBXBuildFile section */
                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 */; };
+               F9B1A2640A3A563E00DA8FAB /* rebase.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = F9B1A2580A3A448800DA8FAB /* rebase.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 */; };
+               F9EC78060A2F8674002A3E39 /* rebase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9EC78050A2F8674002A3E39 /* rebase.cpp */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXBuildRule section */
                };
 /* 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 */
+               F96904880A4333AC00B77D2A /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = F9023C3006D5A227001BBF46 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = F9EC77ED0A2F85F6002A3E39 /* rebase */;
+                       remoteInfo = rebase;
+               };
                F96D5369094A275D008E9EE8 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = F9023C3006D5A227001BBF46 /* Project object */;
                        remoteGlobalIDString = F971EED206D5ACF60041D381;
                        remoteInfo = ObjectDump;
                };
+               F9B1A2680A3A568200DA8FAB /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = F9023C3006D5A227001BBF46 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = F9023C3806D5A23E001BBF46;
+                       remoteInfo = ld;
+               };
+               F9B1A26A0A3A568400DA8FAB /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = F9023C3006D5A227001BBF46 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = F9EC77ED0A2F85F6002A3E39;
+                       remoteInfo = rebase;
+               };
                F9EA73960974999B008B4F1D /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = F9023C3006D5A227001BBF46 /* Project object */;
                        );
                        runOnlyForDeploymentPostprocessing = 1;
                };
+               F9B1A25E0A3A44CB00DA8FAB /* CopyFiles */ = {
+                       isa = PBXCopyFilesBuildPhase;
+                       buildActionMask = 8;
+                       dstPath = /usr/share/man/man1;
+                       dstSubfolderSpec = 0;
+                       files = (
+                               F9B1A2640A3A563E00DA8FAB /* rebase.1 in CopyFiles */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+               };
 /* End PBXCopyFilesBuildPhase section */
 
 /* Begin PBXFileReference section */
                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>"; };
+               F9B1A2580A3A448800DA8FAB /* rebase.1 */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.man; name = rebase.1; path = doc/man/man1/rebase.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>"; };
+               F9EC77EE0A2F85F6002A3E39 /* rebase */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = rebase; sourceTree = BUILT_PRODUCTS_DIR; };
+               F9EC78050A2F8674002A3E39 /* rebase.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = rebase.cpp; path = src/rebase.cpp; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
+               F9EC77EC0A2F85F6002A3E39 /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
                                F9EA7583097882F3008B4F1D /* debugline.h */,
                                F9EA72D4097454FF008B4F1D /* machochecker.cpp */,
                                F971EED706D5AD240041D381 /* ObjectDump.cpp */,
+                               F9EC78050A2F8674002A3E39 /* rebase.cpp */,
                                F97F5028070D0BB200B9FCD7 /* ld64.1 */,
+                               F9B1A2580A3A448800DA8FAB /* rebase.1 */,
                                F9023C3A06D5A23E001BBF46 /* Products */,
                        );
                        sourceTree = "<group>";
                                F9023C3906D5A23E001BBF46 /* ld64 */,
                                F971EED306D5ACF60041D381 /* ObjectDump */,
                                F9EA72CB097454A6008B4F1D /* machocheck */,
+                               F9EC77EE0A2F85F6002A3E39 /* rebase */,
                        );
                        name = Products;
                        sourceTree = "<group>";
                                F9E8D4BE07FCAF2A00FD5801 /* PBXBuildRule */,
                                F9E8D4BD07FCAF2000FD5801 /* PBXBuildRule */,
                        );
-                       buildSettings = {
-                               PRODUCT_NAME = ld64;
-                       };
                        dependencies = (
                        );
                        name = ld;
                        );
                        buildRules = (
                        );
-                       buildSettings = {
-                               PRODUCT_NAME = ObjectDump;
-                       };
                        dependencies = (
                        );
                        name = ObjectDump;
                        );
                        buildRules = (
                        );
-                       buildSettings = {
-                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
-                               GCC_MODEL_TUNING = G5;
-                               INSTALL_PATH = "$(HOME)/bin";
-                               PREBINDING = NO;
-                               PRODUCT_NAME = machocheck;
-                       };
                        dependencies = (
                        );
                        name = machocheck;
                        productReference = F9EA72CB097454A6008B4F1D /* machocheck */;
                        productType = "com.apple.product-type.tool";
                };
+               F9EC77ED0A2F85F6002A3E39 /* rebase */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = F9EC77F00A2F8616002A3E39 /* Build configuration list for PBXNativeTarget "rebase" */;
+                       buildPhases = (
+                               F9EC77EB0A2F85F6002A3E39 /* Sources */,
+                               F9EC77EC0A2F85F6002A3E39 /* Frameworks */,
+                               F9B1A25E0A3A44CB00DA8FAB /* CopyFiles */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = rebase;
+                       productName = rebase;
+                       productReference = F9EC77EE0A2F85F6002A3E39 /* rebase */;
+                       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 = (
+                               F9B1A2670A3A567B00DA8FAB /* all */,
                                F9023C3806D5A23E001BBF46 /* ld */,
+                               F9EC77ED0A2F85F6002A3E39 /* rebase */,
                                F971EED206D5ACF60041D381 /* ObjectDump */,
                                F9EA72CA097454A6008B4F1D /* machocheck */,
                                F96D5368094A2754008E9EE8 /* unit-tests */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
+               F9EC77EB0A2F85F6002A3E39 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               F9EC78060A2F8674002A3E39 /* rebase.cpp in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
 /* End PBXSourcesBuildPhase section */
 
 /* Begin PBXTargetDependency section */
+               F96904890A4333AC00B77D2A /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = F9EC77ED0A2F85F6002A3E39 /* rebase */;
+                       targetProxy = F96904880A4333AC00B77D2A /* PBXContainerItemProxy */;
+               };
                F96D536A094A275D008E9EE8 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = F9023C3806D5A23E001BBF46 /* ld */;
                        target = F971EED206D5ACF60041D381 /* ObjectDump */;
                        targetProxy = F96D536B094A275F008E9EE8 /* PBXContainerItemProxy */;
                };
+               F9B1A2690A3A568200DA8FAB /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = F9023C3806D5A23E001BBF46 /* ld */;
+                       targetProxy = F9B1A2680A3A568200DA8FAB /* PBXContainerItemProxy */;
+               };
+               F9B1A26B0A3A568400DA8FAB /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = F9EC77ED0A2F85F6002A3E39 /* rebase */;
+                       targetProxy = F9B1A26A0A3A568400DA8FAB /* PBXContainerItemProxy */;
+               };
                F9EA73970974999B008B4F1D /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = F9EA72CA097454A6008B4F1D /* machocheck */;
                        buildSettings = {
                                COPY_PHASE_STRIP = NO;
                                CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
+                               DEBUG_INFORMATION_FORMAT = dwarf;
                                GCC_DYNAMIC_NO_PIC = YES;
-                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                GCC_MODEL_TUNING = G5;
                                GCC_OPTIMIZATION_LEVEL = 0;
                                GCC_TREAT_WARNINGS_AS_ERRORS = YES;
                                INSTALL_PATH = /usr/bin;
                                OTHER_CPLUSPLUSFLAGS = "$(OTHER_CPLUSPLUSFLAGS)";
                                OTHER_LDFLAGS = "";
-                               PREBINDING = NO;
                                PRODUCT_NAME = ld64;
                                SECTORDER_FLAGS = "";
                                VERSIONING_SYSTEM = "apple-generic";
                        buildSettings = {
                                COPY_PHASE_STRIP = YES;
                                CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
+                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                GCC_DYNAMIC_NO_PIC = YES;
-                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                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;
                                INSTALL_PATH = /usr/bin;
                                OTHER_CPLUSPLUSFLAGS = "$(OTHER_CPLUSPLUSFLAGS)";
                                OTHER_LDFLAGS = "";
-                               PREBINDING = NO;
                                PRODUCT_NAME = ld64;
                                SECTORDER_FLAGS = "";
+                               VALID_ARCHS = "i386 ppc";
                                VERSIONING_SYSTEM = "apple-generic";
                                WARNING_CFLAGS = "-Wall";
                        };
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                COPY_PHASE_STRIP = NO;
-                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               DEBUG_INFORMATION_FORMAT = dwarf;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                GCC_MODEL_TUNING = G5;
                                GCC_OPTIMIZATION_LEVEL = 0;
                                INSTALL_PATH = "$(HOME)/bin";
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                COPY_PHASE_STRIP = YES;
-                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               DEBUG_INFORMATION_FORMAT = dwarf;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                GCC_MODEL_TUNING = G5;
-                               GCC_OPTIMIZATION_LEVEL = 0;
+                               GCC_OPTIMIZATION_LEVEL = s;
                                INSTALL_PATH = "$(HOME)/bin";
                                OTHER_LDFLAGS = "";
                                OTHER_REZFLAGS = "";
                                PREBINDING = NO;
                                PRODUCT_NAME = ObjectDump;
-                               SECTORDER_FLAGS = "";
                                WARNING_CFLAGS = (
                                        "-Wmost",
                                        "-Wno-four-char-constants",
                        };
                        name = Release;
                };
+               F9B1A26D0A3A568700DA8FAB /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = NO;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               PRODUCT_NAME = all;
+                       };
+                       name = Debug;
+               };
+               F9B1A26E0A3A568700DA8FAB /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = YES;
+                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               PRODUCT_NAME = all;
+                               ZERO_LINK = NO;
+                       };
+                       name = Release;
+               };
                F9EA72D0097454D5008B4F1D /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                COPY_PHASE_STRIP = NO;
+                               DEBUG_INFORMATION_FORMAT = dwarf;
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                GCC_MODEL_TUNING = G5;
+                               GCC_OPTIMIZATION_LEVEL = 0;
                                INSTALL_PATH = "$(HOME)/bin";
                                PREBINDING = NO;
                                PRODUCT_NAME = machocheck;
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                COPY_PHASE_STRIP = YES;
-                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               DEBUG_INFORMATION_FORMAT = dwarf;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                GCC_MODEL_TUNING = G5;
                                INSTALL_PATH = "$(HOME)/bin";
                                PREBINDING = NO;
                        };
                        name = Release;
                };
+               F9EC77F10A2F8616002A3E39 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = NO;
+                               DEBUG_INFORMATION_FORMAT = dwarf;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               INSTALL_PATH = "$(HOME)/bin";
+                               PREBINDING = NO;
+                               PRODUCT_NAME = rebase;
+                       };
+                       name = Debug;
+               };
+               F9EC77F20A2F8616002A3E39 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = YES;
+                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_PREPROCESSOR_DEFINITIONS = "$(GCC_PREPROCESSOR_DEFINITIONS_$(RC_RELEASE))";
+                               GCC_PREPROCESSOR_DEFINITIONS_CurryWeed = __OPEN_SOURCE__;
+                               INSTALL_PATH = /usr/bin;
+                               PREBINDING = NO;
+                               PRODUCT_NAME = rebase;
+                               VALID_ARCHS = "i386 ppc";
+                       };
+                       name = Release;
+               };
 /* End XCBuildConfiguration section */
 
 /* Begin XCConfigurationList section */
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
+               F9B1A26C0A3A568700DA8FAB /* Build configuration list for PBXAggregateTarget "all" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               F9B1A26D0A3A568700DA8FAB /* Debug */,
+                               F9B1A26E0A3A568700DA8FAB /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
                F9EA72CF097454D5008B4F1D /* Build configuration list for PBXNativeTarget "machocheck" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
+               F9EC77F00A2F8616002A3E39 /* Build configuration list for PBXNativeTarget "rebase" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               F9EC77F10A2F8616002A3E39 /* Debug */,
+                               F9EC77F20A2F8616002A3E39 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
 /* End XCConfigurationList section */
        };
        rootObject = F9023C3006D5A227001BBF46 /* Project object */;
index 71c10c46720498b275bead26c407de79fabab1ea..e735f9e2ed0927d4ebb3fa06f8fa621ce1d83429 100644 (file)
@@ -56,9 +56,19 @@ struct x86
        typedef Pointer32<LittleEndian>         P;
        
        enum ReferenceKinds {  kNoFixUp, kFollowOn, kPointer, kPointerWeakImport, kPointerDiff, 
-                                                       kPCRel32, kPCRel32WeakImport };
+                                                       kPCRel32, kPCRel32WeakImport, kAbsolute32 };
 };
 
+struct x86_64
+{
+       typedef Pointer64<LittleEndian>         P;
+       
+       enum ReferenceKinds {  kNoFixUp, kFollowOn, kPointer, kPointerWeakImport, kPointerDiff, kPointerDiff32, 
+                                                       kPCRel32, kPCRel32_1, kPCRel32_2, kPCRel32_4,
+                                                       kBranchPCRel32, kBranchPCRel32WeakImport,
+                                                       kPCRel32GOTLoad, kPCRel32GOTLoadWeakImport,
+                                                       kPCRel32GOT, kPCRel32GOTWeakImport };
+};
 
 
 
index 6110e80b8afbb530abac3bb9e613b89a1c623d84..5d46cbf5dbbfffc36dffbb823eeb64bbf1d4ac80 100644 (file)
@@ -39,6 +39,9 @@ struct uuid_command {
 };
 #endif
 
+#ifndef S_16BYTE_LITERALS
+       #define S_16BYTE_LITERALS 0xE
+#endif
 
 #include "FileAbstraction.hpp"
 #include "Architectures.hpp"
@@ -130,7 +133,7 @@ public:
        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); }
+       void                    set_segname(const char* value)  INLINE { strncpy(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); }
@@ -179,10 +182,10 @@ 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); }
+       void                    set_sectname(const char* value) INLINE { strncpy(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); }
+       void                    set_segname(const char* value)  INLINE { strncpy(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); }
index d40ca7090288613ab3665421ffab052073f41949..c5c120ba5c5d5a627e6df7c056a2292c825937fe 100644 (file)
@@ -385,10 +385,11 @@ std::vector<class ObjectFile::Atom*>* Reader<A>::getJustInTimeAtomsFor(const cha
                if ( result != NULL ) {
                        const Entry* member = (Entry*)&fFileContent[E::get32(result->ran_off)];
                        if ( fInstantiatedEntries.count(member) == 0 ) {
+                               if ( fOptions.fWhyLoad )
+                                       printf("%s forced load of %s(%s)\n", name, this->getPath(), member->getName());
                                // only return these atoms once
                                fInstantiatedEntries.insert(member);
                                ObjectFile::Reader* r = makeObjectReaderForMember(member);
-                               //fprintf(stderr, "%s found in %s(%s)\n", name, this->getPath(), member->getName());
                                return new std::vector<class ObjectFile::Atom*>(r->getAtoms());
                        }
                }
index e9ff931afa4d802fc1bdb39435b710ab1b912318..9cadfbbe3c7446486ce33078bbb6ca03c610254e 100644 (file)
@@ -85,6 +85,7 @@ public:
        virtual Scope                                                           getScope() const                        { return ObjectFile::Atom::scopeGlobal; }
        virtual DefinitionKind                                          getDefinitionKind() const       { return fWeakDefinition ? kExternalWeakDefinition : kExternalDefinition; }
        virtual SymbolTableInclusion                            getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableIn; }
+       virtual bool                                                            dontDeadStrip() const           { return false; }
        virtual bool                                                            isZeroFill() const                      { return false; }
        virtual uint64_t                                                        getSize() const                         { return 0; }
        virtual std::vector<ObjectFile::Reference*>&  getReferences() const             { return fgEmptyReferenceList; }
@@ -131,10 +132,11 @@ 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() {}
+       static bool                                                                             validFile(const uint8_t* fileContent, bool executableOrDylib);
+       static Reader<A>*                                                               make(const uint8_t* fileContent, uint64_t fileLength, const char* path, 
+                                                                                                               bool executableOrDylib, const ObjectFile::ReaderOptions& options)
+                                                                                                               { return new Reader<A>(fileContent, fileLength, path, executableOrDylib, options); }
+       virtual                                                                                 ~Reader() {}
 
        virtual const char*                                                             getPath()                                       { return fPath; }
        virtual time_t                                                                  getModificationTime()           { return 0; }
@@ -168,7 +170,8 @@ private:
 
        struct PathAndFlag { const char* path; bool reExport; };
 
-                                                                                               Reader(const uint8_t* fileContent, uint64_t fileLength, const char* path, const ObjectFile::ReaderOptions& options);
+                                                                                               Reader(const uint8_t* fileContent, uint64_t fileLength, const char* path,
+                                                                                                               bool executableOrDylib, const ObjectFile::ReaderOptions& options);
 
        const char*                                                                     fPath;
        const char*                                                                     fParentUmbrella;
@@ -191,11 +194,11 @@ 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)
+Reader<A>::Reader(const uint8_t* fileContent, uint64_t fileLength, const char* path, bool executableOrDylib, const ObjectFile::ReaderOptions& options)
        : fParentUmbrella(NULL), fDylibInstallPath(NULL), fDylibTimeStamp(0), fDylibtCurrentVersion(0), fDylibCompatibilityVersion(0)
 {
        // sanity check
-       if ( ! validFile(fileContent) )
+       if ( ! validFile(fileContent, executableOrDylib) )
                throw "not a valid mach-o object file";
 
        fPath = strdup(path);
@@ -301,7 +304,7 @@ Reader<A>::Reader(const uint8_t* fileContent, uint64_t fileLength, const char* p
        }
 
        // validate minimal load commands
-       if ( fDylibInstallPath == NULL ) 
+       if ( (fDylibInstallPath == NULL) && (header->filetype() != MH_EXECUTE) ) 
                throw "dylib missing LC_ID_DYLIB load command";
        if ( symbolTable == NULL )
                throw "dylib missing LC_SYMTAB load command";
@@ -404,8 +407,9 @@ 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
+       const char* childInstallPath = child->getInstallPath();
        for (typename std::vector<PathAndFlag>::iterator it = fDependentLibraryPaths.begin(); it != fDependentLibraryPaths.end(); it++) {
-               if ( it->reExport && (strcmp(it->path, child->getPath()) == 0) )
+               if ( it->reExport && ((strcmp(it->path, child->getPath()) == 0) || ((childInstallPath!=NULL) && (strcmp(it->path, childInstallPath)==0))) )
                        return true;
        }
 
@@ -422,44 +426,80 @@ bool Reader<A>::reExports(ObjectFile::Reader* child)
 }
 
 template <>
-bool Reader<ppc>::validFile(const uint8_t* fileContent)
+bool Reader<ppc>::validFile(const uint8_t* fileContent, bool executableOrDylib)
 {
        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;
+       switch ( header->filetype() ) {
+               case MH_DYLIB:
+               case MH_DYLIB_STUB:
+                       return true;
+               case MH_EXECUTE:
+                       return executableOrDylib;
+               default:
+                       return false;
+       }
 }
 
 template <>
-bool Reader<ppc64>::validFile(const uint8_t* fileContent)
+bool Reader<ppc64>::validFile(const uint8_t* fileContent, bool executableOrDylib)
 {
        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;
+       switch ( header->filetype() ) {
+               case MH_DYLIB:
+               case MH_DYLIB_STUB:
+                       return true;
+               case MH_EXECUTE:
+                       return executableOrDylib;
+               default:
+                       return false;
+       }
 }
 
 template <>
-bool Reader<x86>::validFile(const uint8_t* fileContent)
+bool Reader<x86>::validFile(const uint8_t* fileContent, bool executableOrDylib)
 {
        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;
+       switch ( header->filetype() ) {
+               case MH_DYLIB:
+               case MH_DYLIB_STUB:
+                       return true;
+               case MH_EXECUTE:
+                       return executableOrDylib;
+               default:
+                       return false;
+       }
 }
 
+template <>
+bool Reader<x86_64>::validFile(const uint8_t* fileContent, bool executableOrDylib)
+{
+       const macho_header<P>* header = (const macho_header<P>*)fileContent;
+       if ( header->magic() != MH_MAGIC_64 )
+               return false;
+       if ( header->cputype() != CPU_TYPE_X86_64 )
+               return false;
+       switch ( header->filetype() ) {
+               case MH_DYLIB:
+               case MH_DYLIB_STUB:
+                       return true;
+               case MH_EXECUTE:
+                       return executableOrDylib;
+               default:
+                       return false;
+       }
+}
 
 
 
index 508be473a24b05c3cc1dec70422d1b182c1e52d0..7458d59e84f78c1565fbffcf6a4dda35ad67b647 100644 (file)
@@ -31,6 +31,7 @@
 #include <sys/param.h>
 #include <mach-o/ppc/reloc.h>
 #include <mach-o/stab.h>
+#include <mach-o/x86_64/reloc.h>
 #ifndef S_ATTR_DEBUG
  #define S_ATTR_DEBUG 0x02000000
 #endif
@@ -99,7 +100,7 @@ public:
        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 uint64_t                getTargetOffset() const                                                 { return (int64_t)((int32_t)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(); }
@@ -127,10 +128,13 @@ Reference<A>::Reference(Kinds kind, const AtomAndOffset& at, const AtomAndOffset
  : 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();
+       // make reference a by-name unless:
+       // - the reference type is only used with direct references
+       // - the target is translation unit scoped
+       if ( (kind != A::kNoFixUp) && (kind != A::kFollowOn) 
+               && (toTarget.atom->getScope() != ObjectFile::Atom::scopeTranslationUnit) ) {
                //fprintf(stderr, "Reference(): changing to by-name %p %s, target scope=%d\n", toTarget.atom, fToTargetName, toTarget.atom->getScope());
+               fToTargetName = toTarget.atom->getName();
                fToTarget.atom = NULL;
        }
        ((class BaseAtom*)at.atom)->addReference(this);
@@ -181,15 +185,10 @@ private:
 
 template <typename A>
 Segment<A>::Segment(const macho_section<typename A::P>* sect) 
- :     fSection(sect), fWritable(false),  fExecutable(false) 
+ :     fSection(sect), fWritable(true),  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 ) {
+       if ( strcmp(fSection->segname(), "__TEXT") == 0 ) {
+               fWritable = false;
                fExecutable = true;
        }
        else if ( strcmp(fSection->segname(), "__IMPORT") == 0 ) {
@@ -245,8 +244,8 @@ public:
        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 SymbolTableInclusion                            getSymbolTableInclusion() const { return fSymbolTableInclusion; }
+       virtual bool                                                            dontDeadStrip() const                   { return ((fSymbol->n_desc() & (N_NO_DEAD_STRIP|REFERENCED_DYNAMICALLY)) != 0); }
        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); }
@@ -287,6 +286,7 @@ protected:
        ReferenceVector                                                         fReferences;
        std::vector<ObjectFile::LineInfo>                       fLineInfo;
        ObjectFile::Atom::Scope                                         fScope;
+       SymbolTableInclusion                                            fSymbolTableInclusion;
        uint8_t                                                                         fAlignment;
 };
 
@@ -306,9 +306,7 @@ SymbolAtom<A>::SymbolAtom(Reader<A>& owner, const macho_nlist<P>* symbol, const
                // 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);
        }
@@ -347,14 +345,42 @@ SymbolAtom<A>::SymbolAtom(Reader<A>& owner, const macho_nlist<P>* symbol, const
                case S_8BYTE_LITERALS:
                        setSize(8);
                        break;
+               case S_16BYTE_LITERALS:
+                       setSize(16);
+                       break;
                case S_CSTRING_LITERALS:
                        setSize(strlen((char*)(fOwner.fHeader) + section->offset() + fAddress - section->addr()) + 1);
+                       break;
                case S_REGULAR:
                case S_ZEROFILL:
                case S_COALESCED:
                        // size calculate later after next atom is found
                        break;
        }
+       
+       // compute whether this atom needs to be in symbol table
+       if ( (fSymbol->n_desc() & REFERENCED_DYNAMICALLY) != 0) {
+               fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableInAndNeverStrip;
+       }
+       else if (  fOwner.fOptions.fForFinalLinkedImage 
+                       && ((section->flags() & SECTION_TYPE) == S_COALESCED) 
+                       && ((section->flags() & S_ATTR_NO_TOC) == S_ATTR_NO_TOC) 
+                       && ((section->flags() & S_ATTR_STRIP_STATIC_SYMS) == S_ATTR_STRIP_STATIC_SYMS) 
+                       && (strcmp(section->sectname(), "__eh_frame") == 0) ) {
+               // .eh symbols exist so the linker can associate them with functions
+               // removing them from final linked images is a big space savings rdar://problem/4180168
+               fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableNotIn;
+       }
+       else if (  fOwner.fOptions.fForFinalLinkedImage 
+                       && ((section->flags() & SECTION_TYPE) == S_REGULAR) 
+                       && (strncmp(section->sectname(), "__gcc_except_tab", 16) == 0) 
+                       && (strncmp(this->getName(),     "GCC_except_table", 16) == 0) ) {
+               // GCC_except_table* symbols don't need to exist in final linked image
+               fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableNotIn;
+       }
+       else {
+               fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
+       }
 }
 
 
@@ -363,14 +389,23 @@ 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);
+       if ( fSection->flags() & S_ATTR_SOME_INSTRUCTIONS ) {
+               // For code, the aligment is based just on the section alignment and code address
+               if ( fAddress == 0 )
+                       fAlignment = fSection->align();
+               else
+                       fAlignment = std::min((uint8_t)__builtin_ctz(fAddress), (uint8_t)fSection->align());
+       }
+       else {
+               // For data, 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);
+       }
 }
 
 
@@ -476,6 +511,7 @@ public:
        virtual bool                                                            isZeroFill() const                              { return true; }
        virtual SymbolTableInclusion                            getSymbolTableInclusion() const { return ((fSymbol->n_desc() & REFERENCED_DYNAMICALLY) != 0)
                                                                                                                                                                                ? ObjectFile::Atom::kSymbolTableInAndNeverStrip : ObjectFile::Atom::kSymbolTableIn; }
+       virtual bool                                                            dontDeadStrip() const                   { return ((fSymbol->n_desc() & (N_NO_DEAD_STRIP|REFERENCED_DYNAMICALLY)) != 0); }
        virtual uint64_t                                                        getSize() const                                 { return fSymbol->n_value(); }
        virtual std::vector<ObjectFile::Reference*>&  getReferences() const                     { return fgNoReferences; }
        virtual bool                                                            mustRemainInSection() const             { return true; }
@@ -488,8 +524,8 @@ public:
        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                                                            addReference(ObjectFile::Reference* ref) { throw "ld64: can't add references"; }
+       virtual void                                                            addLineInfo(const  ObjectFile::LineInfo& info)  { throw "ld64: can't add line info to tentative definition"; }
        virtual void                                                            alignAtLeast(uint8_t align)             { }
 
 protected:
@@ -568,7 +604,8 @@ public:
        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 ObjectFile::Atom::SymbolTableInclusion getSymbolTableInclusion() const  { return fSymbolTableInclusion; }
+       virtual bool                                                            dontDeadStrip() const                   { return fDontDeadStrip; }
        virtual bool                                                            isZeroFill() const;
        virtual uint64_t                                                        getSize() const                                 { return fSize; }
        virtual std::vector<ObjectFile::Reference*>&  getReferences() const                     { return (std::vector<ObjectFile::Reference*>&)(fReferences); }
@@ -580,10 +617,10 @@ public:
        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                                                            setScope(ObjectFile::Atom::Scope newScope)      { fScope = 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                                                            addLineInfo(const  ObjectFile::LineInfo& info) { fprintf(stderr, "ld64: can't add line info to anonymous symbol %s from %s\n", this->getDisplayName(), this->getFile()->getPath()); }
        virtual void                                                            alignAtLeast(uint8_t align)             { }
        BaseAtom*                                                                       redirectTo()                                    { return fRedirect; }
        bool                                                                            isWeakImportStub()                              { return fWeakImportStub; }
@@ -609,14 +646,18 @@ protected:
        Segment<A>*                                                                     fSegment;
        ReferenceVector                                                         fReferences;
        BaseAtom*                                                                       fRedirect;
+       bool                                                                            fDontDeadStrip;
        bool                                                                            fWeakImportStub;
        bool                                                                            fReallyNonLazyPointer;  // HACK until compiler stops emitting anonymous non-lazy pointers
+       ObjectFile::Atom::SymbolTableInclusion          fSymbolTableInclusion;
+       ObjectFile::Atom::Scope                                         fScope;
 };
 
 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)
+ : fOwner(owner), fSynthesizedName(NULL), fSection(section), fAddress(addr), fSize(size), fSegment(NULL), fDontDeadStrip(true),
+       fWeakImportStub(false), fReallyNonLazyPointer(false), fSymbolTableInclusion(ObjectFile::Atom::kSymbolTableNotIn),
+       fScope(ObjectFile::Atom::scopeTranslationUnit)
 {
        fSegment = new Segment<A>(fSection);
        fRedirect = this;
@@ -628,32 +669,62 @@ AnonymousAtom<A>::AnonymousAtom(Reader<A>& owner, const macho_section<P>* sectio
                        }
                        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
+                       if ( (strcmp(section->sectname(), "__class") == 0) && (strcmp(section->segname(), "__OBJC") == 0) && owner.fAppleObjc ) {
+                               // special case ObjC classes to synthesize .objc_class_name_* symbols, for Apple runtime only
+                               uint32_t classNameAddr =  P::getP(*(pint_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr + 2*sizeof(pint_t) - section->addr()));
+                               const char* str = (char*)(owner.fHeader) + section->offset() + classNameAddr - section->addr();
+                               asprintf((char**)&fSynthesizedName, ".objc_class_name_%s", str);
+                               if ( fOwner.fOptions.fForFinalLinkedImage ) 
+                                       fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableIn;
+                               else
+                                       fSymbolTableInclusion = ObjectFile::Atom::kSymbolTableInAsAbsolute;
+                               fScope = ObjectFile::Atom::scopeGlobal;
+                       }
+                       else if ( strcmp(fSection->sectname(), "__cstring") == 0 ) {
+                               // handle .o files created by old ld64 -r that are missing cstring section type
+                               const char* str = (char*)(owner.fHeader) + section->offset() + addr - section->addr();
+                               asprintf((char**)&fSynthesizedName, "cstring=%s", str);
+                       }
+                       break;
                case S_CSTRING_LITERALS:
                        {
                                const char* str = (char*)(owner.fHeader) + section->offset() + addr - section->addr();
                                asprintf((char**)&fSynthesizedName, "cstring=%s", str);
+                               fScope = ObjectFile::Atom::scopeLinkageUnit;
+                               fDontDeadStrip = false;
                        }
                        break;
                case S_4BYTE_LITERALS:
                        {
                                uint32_t value =  E::get32(*(uint32_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
                                asprintf((char**)&fSynthesizedName, "4-byte-literal=0x%08X", value);
+                               fScope = ObjectFile::Atom::scopeLinkageUnit;
+                               fDontDeadStrip = false;
                        }
                        break;
                case S_8BYTE_LITERALS:
                        {
                                uint64_t value =  E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
                                asprintf((char**)&fSynthesizedName, "8-byte-literal=0x%016llX", value);
+                               fScope = ObjectFile::Atom::scopeLinkageUnit;
+                               fDontDeadStrip = false;
+                       }
+                       break;
+               case S_16BYTE_LITERALS:
+                       {
+                               uint64_t value1 =  E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
+                               uint64_t value2 =  E::get64(*(uint64_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr + 8 - section->addr()));
+                               asprintf((char**)&fSynthesizedName, "16-byte-literal=0x%016llX,%016llX", value1, value2);
+                               fScope = ObjectFile::Atom::scopeLinkageUnit;
+                               fDontDeadStrip = false;
                        }
                        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());
+                               uint32_t literalNameAddr =  P::getP(*(pint_t*)(((uint8_t*)owner.fHeader) + section->offset() + addr - section->addr()));
+                               const char* str = (char*)(owner.fHeader) + section->offset() + literalNameAddr - section->addr();
+                               asprintf((char**)&fSynthesizedName, "literal-pointer@%s@%s@%s", section->segname(), section->sectname(), str);
+                               fScope = ObjectFile::Atom::scopeLinkageUnit;
                        }
                        break;
                case S_MOD_INIT_FUNC_POINTERS:
@@ -680,22 +751,27 @@ AnonymousAtom<A>::AnonymousAtom(Reader<A>& owner, const macho_section<P>* sectio
                                        if ( staticAtom != NULL )
                                                fRedirect = staticAtom;
                                }
+                               fScope = ObjectFile::Atom::scopeLinkageUnit;
                        }
                        break;
                case S_LAZY_SYMBOL_POINTERS:
                case S_NON_LAZY_SYMBOL_POINTERS:
                        {
+                               fDontDeadStrip = false;
+                               fScope = ObjectFile::Atom::scopeLinkageUnit;
                                uint32_t index = (fAddress - fSection->addr()) / sizeof(pint_t);
                                index += fSection->reserved1();
                                uint32_t symbolIndex = E::get32(fOwner.fIndirectTable[index]);
                                if ( symbolIndex == INDIRECT_SYMBOL_LOCAL ) {
                                        // Silly codegen with non-lazy pointer to a local symbol
-                                       // 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)));
+                                       // All atoms not created yet, so we need to scan symbol table
                                        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) ) {
+                                               if ( ((sym->n_type() & N_TYPE) == N_SECT) 
+                                                && ((sym->n_type() & N_STAB) == 0) 
+                                                && (sym->n_value() == nonLazyPtrValue) ) {
                                                        const char* name = &fOwner.fStrings[sym->n_strx()];
                                                        char* str = new char[strlen(name)+16];
                                                        strcpy(str, name);
@@ -703,10 +779,11 @@ AnonymousAtom<A>::AnonymousAtom(Reader<A>& owner, const macho_section<P>* sectio
                                                        fSynthesizedName = str;
                                                        // add direct reference to target later, because its atom may not be constructed yet
                                                        fOwner.fLocalNonLazys.push_back(this);
+                                                       fScope = ObjectFile::Atom::scopeTranslationUnit;
                                                        return;
                                                }
                                        }
-                                       throwf("malformed .o file: non-lazy-pointer with value 0x%08X missing symbol", nonLazyPtrValue);
+                                       throwf("malformed .o file: non-lazy-pointer at address 0x%08X with value 0x%0llX missing symbol", addr, (uint64_t)nonLazyPtrValue);
                                }
                                const macho_nlist<P>* targetSymbol = &fOwner.fSymbols[symbolIndex];
                                const char* name = &fOwner.fStrings[targetSymbol->n_strx()];
@@ -718,10 +795,17 @@ AnonymousAtom<A>::AnonymousAtom(Reader<A>& owner, const macho_section<P>* sectio
                                        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);
+                               if ( (targetSymbol->n_type() & N_EXT) == 0 ) {
+                                       // target is translation unit scoped, so add direct reference to target
+                                       //fOwner.makeReference(A::kPointer, addr, targetSymbol->n_value());
+                                       new Reference<A>(A::kPointer, AtomAndOffset(this), fOwner.findAtomAndOffset(targetSymbol->n_value()));
+                               }
+                               else {  
+                                       if ( fOwner.isWeakImportSymbol(targetSymbol) )
+                                               new Reference<A>(A::kPointerWeakImport, AtomAndOffset(this), name, 0);
+                                       else
+                                               new Reference<A>(A::kPointer, AtomAndOffset(this), name, 0);
+                               }
                        }
                        break;
                default:
@@ -752,31 +836,24 @@ 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;
-       }
+               return ObjectFile::Atom::scopeTranslationUnit;
+       else    
+               return fScope;
 }
 
 template <typename A>
 ObjectFile::Atom::DefinitionKind AnonymousAtom<A>::getDefinitionKind() const
 {
        if ( fReallyNonLazyPointer )
-               return  ObjectFile::Atom::kWeakDefinition;
+               return  ObjectFile::Atom::kRegularDefinition;
        // 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_16BYTE_LITERALS:
                case S_NON_LAZY_SYMBOL_POINTERS:
+               case S_LITERAL_POINTERS:
                        return ObjectFile::Atom::kWeakDefinition;
                default:
                        return ObjectFile::Atom::kRegularDefinition;
@@ -793,8 +870,6 @@ bool AnonymousAtom<A>::isZeroFill() const
 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);
@@ -814,6 +889,8 @@ uint8_t AnonymousAtom<A>::getAlignment() const
                        return 2;
                case S_8BYTE_LITERALS:
                        return 3;
+               case S_16BYTE_LITERALS:
+                       return 4;
                case S_NON_LAZY_SYMBOL_POINTERS:
                        return (uint8_t)log2(sizeof(pint_t));
                default:
@@ -906,7 +983,9 @@ private:
        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);
+       Reference<A>*                                                           makeReferenceToSymbol(Kinds kind, uint32_t atAddr, const macho_nlist<P>* toSymbol, uint32_t toOffset);
        void                                                                            validSectionType(uint8_t type);
+       void                                                                            handleAnonymousNonLazyPointers(const macho_section<P>* sect);
 
        BaseAtom*                                                                       findAtomByName(const char*);
 
@@ -923,6 +1002,7 @@ private:
        std::map<uint32_t, BaseAtom*>                           fAddrToAtom;
        std::vector<class AnonymousAtom<A>*>            fLocalNonLazys;
        ObjectFile::Reader::DebugInfoKind                       fDebugInfo;
+       bool                                                                            fHasUUID;
        const macho_section<P>*                                         fDwarfDebugInfoSect;
        const macho_section<P>*                                         fDwarfDebugAbbrevSect;
        const macho_section<P>*                                         fDwarfDebugLineSect;
@@ -930,15 +1010,56 @@ private:
        const char*                                                                     fDwarfTranslationUnitFile;
        std::map<uint32_t,const char*>                          fDwarfIndexToFile;
        std::vector<Stab>                                                       fStabs;
+       bool                                                                            fAppleObjc;
 };
 
+// usually do nothing
+template <typename A> void Reader<A>::handleAnonymousNonLazyPointers(const macho_section<P>* sect) {  }
+
+// HACK for ppc64, need to split of anonymous non-lazy-pointers because they must be 8-byte aligned to work with ld instruction
+template <> void 
+Reader<ppc64>::handleAnonymousNonLazyPointers(const macho_section<P>* dataSect) { 
+       if ( (dataSect->size() >= sizeof(pint_t)) 
+               && (dataSect->align() >= log2(sizeof(pint_t)))
+               && (strcmp(dataSect->sectname(), "__data") == 0)
+               && (strcmp(dataSect->segname(), "__DATA") == 0) ) {
+                       std::set<uint32_t> lo14targets;
+                       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()];
+                       for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
+                               if ( strncmp(sect->sectname(), "__text", 6) == 0 ) {
+                                       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 ) {
+                                                       const macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)r;
+                                                       if ( sreloc->r_type() == PPC_RELOC_LO14_SECTDIFF ) {
+                                                               lo14targets.insert(sreloc->r_value());
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                       // walk backwards so that newly created anonymous atoms do not mask misalignmented
+                       for (std::set<uint32_t>::reverse_iterator it=lo14targets.rbegin(); it != lo14targets.rend(); it++) {
+                               uint32_t targetOfLO14 = *it;
+                               AtomAndOffset found = this->findAtomAndOffset(targetOfLO14);
+                               if ( (found.offset & 0x7) != 0 ) {
+                                       AnonymousAtom<ppc64>* newAtom = new AnonymousAtom<ppc64>(*this, dataSect, targetOfLO14, sizeof(pint_t));
+                                       newAtom->fReallyNonLazyPointer = true;
+                                       fAtoms.push_back(newAtom);
+                                       fAddrToAtom[targetOfLO14] = newAtom;
+                               }
+                       }
+       }
+}
 
 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)
+        fDebugInfo(kDebugInfoNone), fHasUUID(false), fDwarfDebugInfoSect(NULL), fDwarfDebugAbbrevSect(NULL),
+         fDwarfTranslationUnitDir(NULL), fDwarfTranslationUnitFile(NULL), fAppleObjc(false)
 {
        // sanity check
        if ( ! validFile(fileContent) )
@@ -949,6 +1070,8 @@ Reader<A>::Reader(const uint8_t* fileContent, const char* path, time_t modTime,
        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;
+       uint32_t undefinedStartIndex = 0;
+       uint32_t undefinedEndIndex = 0;
        for (uint32_t i = 0; i < cmd_count; ++i) {
                switch (cmd->cmd()) {
                    case LC_SYMTAB:
@@ -963,11 +1086,12 @@ Reader<A>::Reader(const uint8_t* fileContent, const char* path, time_t modTime,
                                {
                                        const macho_dysymtab_command<P>* dsymtab = (struct macho_dysymtab_command<P>*)cmd;
                                        fIndirectTable = (uint32_t*)((char*)fHeader + dsymtab->indirectsymoff());
+                                       undefinedStartIndex = dsymtab->iundefsym();
+                                       undefinedEndIndex = undefinedStartIndex + dsymtab->nundefsym();
                                }
                                break;
                    case LC_UUID:
-                               if (getDebugInfoKind() != kDebugInfoDwarf)
-                                       fDebugInfo = kDebugInfoStabsUUID;
+                               fHasUUID = true;
                                break;
 
                        default:
@@ -1004,6 +1128,7 @@ Reader<A>::Reader(const uint8_t* fileContent, const char* path, time_t modTime,
                                                case S_COALESCED:
                                                case S_4BYTE_LITERALS:
                                                case S_8BYTE_LITERALS:
+                                               case S_16BYTE_LITERALS:
                                                case S_CSTRING_LITERALS:
                                                        {
                                                                BaseAtom* newAtom = new SymbolAtom<A>(*this, &sym, section);
@@ -1037,6 +1162,9 @@ Reader<A>::Reader(const uint8_t* fileContent, const char* path, time_t modTime,
                        else if ( (type == N_UNDF) && (sym.n_value() != 0) ) {
                                fAtoms.push_back(new TentativeAtom<A>(*this, &sym));
                        }
+                       else if ( (type == N_ABS) && (strncmp(&fStrings[sym.n_strx()], ".objc_class_name_", 16) == 0) ) {
+                               fAppleObjc = true;
+                       }
                }
        }
 
@@ -1073,6 +1201,17 @@ Reader<A>::Reader(const uint8_t* fileContent, const char* path, time_t modTime,
                        case S_8BYTE_LITERALS:
                                atomSize = 8;
                                break;
+                       case S_16BYTE_LITERALS:
+                               atomSize = 16;
+                               break;
+                       case S_REGULAR:
+                               // special case ObjC classes to synthesize .objc_class_name_* symbols
+                               if ( (strcmp(sect->sectname(), "__class") == 0) && (strcmp(sect->segname(), "__OBJC") == 0) && fAppleObjc ) {
+                                       // gcc sometimes over aligns class structure
+                                       uint32_t align = 1 << sect->align();
+                                       atomSize = ((12 * sizeof(pint_t)) + align-1) & (-align);
+                                       }
+                               break;
                }
                if ( atomSize != 0 ) {
                        for(uint32_t sectOffset=0; sectOffset < sect->size(); sectOffset += atomSize) {
@@ -1143,46 +1282,12 @@ Reader<A>::Reader(const uint8_t* fileContent, const char* path, time_t modTime,
                                        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
+                                               // HACK until compiler stops generated anonymous non-lazy pointers rdar://problem/4513414
+                                               handleAnonymousNonLazyPointers(sect); 
+                                               // if there is not an atom already at the start of this section, add an anonymous one
                                                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;
@@ -1241,6 +1346,49 @@ Reader<A>::Reader(const uint8_t* fileContent, const char* path, time_t modTime,
                }
        }
 
+       // check of object file that defines no classes, but uses classes
+       if ( !fAppleObjc ) {
+               for (uint32_t i=undefinedStartIndex; i < undefinedEndIndex; ++i) {
+                       const macho_nlist<P>& sym = fSymbols[i];
+                       if ( (sym.n_type() & N_STAB) == 0 ) {
+                               if ( ((sym.n_type() & N_TYPE) == N_UNDF) && (strncmp(&fStrings[sym.n_strx()], ".objc_class_name_", 16) == 0) ) {
+                                       fAppleObjc = true;
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       // add objective-c references
+       if ( fAppleObjc ) {
+               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 ( (strcmp(sect->sectname(), "__class") == 0) && (strcmp(sect->segname(), "__OBJC") == 0) ) {
+                               // gcc sometimes over aligns class structure
+                               uint32_t align = 1 << sect->align();
+                               uint32_t classSize = ((12 * sizeof(pint_t)) + align-1) & (-align);
+                               for (uint32_t offset = 0; offset < sect->size(); offset += classSize) {
+                                       // add by-name reference to super class
+                                       uint32_t superClassNameAddr =  P::getP(*(pint_t*)(((uint8_t*)fHeader) + sect->offset() + offset + sizeof(pint_t)));
+                                       const char* superStr = (char*)(fHeader) + sect->offset() + superClassNameAddr - sect->addr();
+                                       const char* superClassName;
+                                       asprintf((char**)&superClassName, ".objc_class_name_%s", superStr);
+                                       makeByNameReference(A::kNoFixUp, sect->addr()+offset+sizeof(pint_t), superClassName, 0);
+                               }
+                       }
+                       else if ( (strcmp(sect->sectname(), "__cls_refs") == 0) && (strcmp(sect->segname(), "__OBJC") == 0) ) {
+                               for (uint32_t offset = 0; offset < sect->size(); offset += sizeof(pint_t)) {
+                                       // scan through __cls_refs and add by-name reference for each required class
+                                       uint32_t classNameAddr =  P::getP(*(pint_t*)(((uint8_t*)fHeader) + sect->offset() + offset));
+                                       const char* classStr = (char*)(fHeader) + sect->offset() + classNameAddr - sect->addr();
+                                       const char* className;
+                                       asprintf((char**)&className, ".objc_class_name_%s", classStr);
+                                       makeByNameReference(A::kNoFixUp, sect->addr()+offset, className, 0);
+                               }
+                       }
+               }
+       }
+
        // add direct references to local non-lazy-pointers, can do this now that all atoms are constructed
        for (typename std::vector<AnonymousAtom<A>*>::iterator it=fLocalNonLazys.begin(); it != fLocalNonLazys.end(); it++) {
                AnonymousAtom<A>* localNonLazy = *it;
@@ -1273,12 +1421,15 @@ Reader<A>::Reader(const uint8_t* fileContent, const char* path, time_t modTime,
        // 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;
+               // compiler sometimes emits emtpty dwarf sections when there is no debug info, skip those
+               if ( (fDwarfDebugInfoSect != NULL) && (fDwarfDebugInfoSect->size() != 0) ) {
+                       if ( !read_comp_unit(&fDwarfTranslationUnitFile, &fDwarfTranslationUnitDir, &stmtList) ) {
+                               // if can't parse dwarf, warn and give up
+                               fDwarfTranslationUnitFile = NULL;
+                               fDwarfTranslationUnitDir = NULL;
+                               fprintf(stderr, "ld64: warning can't parse dwarf compilation unit info in %s\n", this->getPath());
+                               fDebugInfo = kDebugInfoNone;
+                       }
                }
        }
 
@@ -1297,9 +1448,13 @@ Reader<A>::Reader(const uint8_t* fileContent, const char* path, time_t modTime,
                                        uint32_t curAtomOffset = 0;
                                        uint32_t curAtomAddress = 0;
                                        uint32_t curAtomSize = 0;
-                                       while ( line_next (lines, &result, line_stop_line) ) {
+                                       while ( line_next (lines, &result, line_stop_pc) ) {
                                                // for performance, see if in next pc is in current atom
-                                               if ( (curAtom != NULL) && (result.pc <= curAtomAddress+curAtomSize) && (curAtomAddress <= result.pc) ) {
+                                               if ( (curAtom != NULL) && (curAtomAddress <= result.pc) && (result.pc < (curAtomAddress+curAtomSize)) ) {
+                                                       curAtomOffset = result.pc - curAtomAddress;
+                                               }
+                                               // or pc at end of current atom
+                                               else if ( result.end_of_sequence && (curAtom != NULL) && (result.pc == (curAtomAddress+curAtomSize)) ) {
                                                        curAtomOffset = result.pc - curAtomAddress;
                                                }
                                                else {
@@ -1309,7 +1464,7 @@ Reader<A>::Reader(const uint8_t* fileContent, const char* path, time_t modTime,
                                                        if ( curAtom == NULL )
                                                                break; // file has line info but no functions
                                                        curAtomOffset   = ao.offset;
-                                                       curAtomAddress  = result.pc;
+                                                       curAtomAddress  = result.pc - ao.offset;
                                                        curAtomSize             = curAtom->getSize();
                                                }
                                                const char* filename;
@@ -1325,8 +1480,12 @@ Reader<A>::Reader(const uint8_t* fileContent, const char* path, time_t modTime,
                                                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);
+                                               //fprintf(stderr, "addr=0x%08llX, line=%lld, file=%s, atom=%s, atom.size=0x%X, end=%d\n", 
+                                               //              result.pc, result.line, filename, curAtom->getDisplayName(), curAtomSize, result.end_of_sequence);
                                                ((BaseAtom*)curAtom)->addLineInfo(info);
+                                               if ( result.end_of_sequence ) {
+                                                       curAtom = NULL;
+                                               }
                                        }
                                        line_free(lines);
                                }
@@ -1346,10 +1505,11 @@ Reader<A>::Reader(const uint8_t* fileContent, const char* path, time_t modTime,
                enum { start, inBeginEnd, inFun } state = start;
                for (uint32_t symbolIndex = 0; symbolIndex < fSymbolCount; ++symbolIndex ) {
                        const macho_nlist<P>* sym = &fSymbols[symbolIndex];
+                       bool useStab = true;
                        uint8_t type = sym->n_type();
                        const char* symString = (sym->n_strx() != 0) ? &fStrings[sym->n_strx()] : NULL;
                        if ( (type & N_STAB) != 0 ) {
-                               fDebugInfo = kDebugInfoStabs;
+                               fDebugInfo =  (fHasUUID ? kDebugInfoStabsUUID : kDebugInfoStabs);
                                Stab stab;
                                stab.atom       = NULL;
                                stab.type       = type;
@@ -1403,6 +1563,7 @@ Reader<A>::Reader(const uint8_t* fileContent, const char* path, time_t modTime,
                                                                }
                                                                if ( stab.atom == NULL ) {
                                                                        fprintf(stderr, "can't find atom for N_GSYM stabs %s in %s\n", symString, path);
+                                                                       useStab = false;
                                                                }
                                                                break;
                                                        case N_FUN:
@@ -1506,7 +1667,8 @@ Reader<A>::Reader(const uint8_t* fileContent, const char* path, time_t modTime,
                                                break;
                                }
                                // add to list of stabs for this .o file
-                               fStabs.push_back(stab);
+                               if ( useStab )
+                                       fStabs.push_back(stab);
                        }
                }
        }
@@ -1525,6 +1687,18 @@ Reader<A>::Reader(const uint8_t* fileContent, const char* path, time_t modTime,
 #endif
 }
 
+template <>
+void Reader<x86_64>::validSectionType(uint8_t type)
+{
+       switch ( type ) {
+               case S_SYMBOL_STUBS:
+                       throw "symbol_stub sections not valid in x86_64 object files";
+               case S_LAZY_SYMBOL_POINTERS:
+                       throw "lazy pointer sections not valid in x86_64 object files";
+               case S_NON_LAZY_SYMBOL_POINTERS:
+                       throw "non lazy pointer sections not valid in x86_64 object files";
+       }
+}
 
 template <typename A>
 void Reader<A>::validSectionType(uint8_t type)
@@ -1600,10 +1774,51 @@ Reference<A>* Reader<A>::makeReferenceToEH(const char* ehName, pint_t ehAtomAddr
        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)      ;
+       return makeReference(A::kNoFixUp, funcAddr, ehAtomAddress);
 }
 
 
+template <>
+Reference<x86_64>* Reader<x86_64>::makeByNameReference(Kinds kind, uint32_t atAddr, const char* toName, uint32_t toOffset)
+{
+       // x86_64 uses external relocations everywhere, so external relocations do not imply by-name references
+       // instead check scope of target
+       BaseAtom* target = findAtomByName(toName);
+       if ( (target != NULL) && (target->getScope() == ObjectFile::Atom::scopeTranslationUnit) )
+               return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), AtomAndOffset(target, toOffset));
+       else
+               return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), toName, toOffset);
+}
+
+template <>
+Reference<x86_64>* Reader<x86_64>::makeReferenceToSymbol(Kinds kind, uint32_t atAddr, const macho_nlist<P>* toSymbol, uint32_t toOffset)
+{
+       // x86_64 uses external relocations everywhere, so external relocations do not imply by-name references
+       // instead check scope of target
+       if ( ((toSymbol->n_type() & N_TYPE) == N_SECT) && ((toSymbol->n_type() & N_EXT) == 0) ) 
+               return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), findAtomAndOffset(toSymbol->n_value(), toSymbol->n_value()+toOffset));
+       else
+               return new Reference<x86_64>(kind, findAtomAndOffset(atAddr), &fStrings[toSymbol->n_strx()], toOffset);
+}
+
+
+template <>
+Reference<x86_64>* Reader<x86_64>::makeReferenceToEH(const char* ehName, pint_t ehAtomAddress, const macho_section<P>* ehSect)
+{
+       // add a direct reference from function atom to its eh frame atom
+       // for x86_64 the __eh_frame section contains the addends, so need to use relocs to find target
+       uint32_t ehAtomDeltaSectionOffset = ehAtomAddress + 8 - ehSect->addr(); // offset 8 in eh info is delta to function
+       const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((char*)(fHeader) + ehSect->reloff());
+       const macho_relocation_info<P>* relocsEnd = &relocs[ehSect->nreloc()];
+       for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
+               if ( (reloc->r_address() == ehAtomDeltaSectionOffset) && (reloc->r_type() == X86_64_RELOC_UNSIGNED) ) {
+                       uint32_t funcAddr = fSymbols[reloc->r_symbolnum()].n_value();
+                       return makeReference(x86_64::kNoFixUp, funcAddr, ehAtomAddress);
+               }
+       }
+       fprintf(stderr, "ld64: warning, can't find matching function for eh symbol %s\n", ehName);
+       return NULL;
+}
 
 template <typename A>
 AtomAndOffset Reader<A>::findAtomAndOffset(uint32_t addr)
@@ -1955,6 +2170,18 @@ bool Reader<x86>::validFile(const uint8_t* fileContent)
        return true;
 }
 
+template <>
+bool Reader<x86_64>::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_X86_64 )
+               return false;
+       if ( header->filetype() != MH_OBJECT )
+               return false;
+       return true;
+}
 
 
 template <typename A>
@@ -2087,7 +2314,7 @@ bool Reader<A>::addRelocReference_powerpc(const macho_section<typename A::P>* se
                                                Reference<A>* ref = makeReference(A::kAbsLow14, srcAddr, dstAddr);
                                                BaseAtom* target = ((BaseAtom*)&(ref->getTarget()));
                                                if ( target != NULL )
-                                                       target->alignAtLeast(2);
+                                                       target->alignAtLeast(3);
                                        }
                                }
                                break;
@@ -2236,7 +2463,7 @@ bool Reader<A>::addRelocReference_powerpc(const macho_section<typename A::P>* se
                                        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);
+                                               target->alignAtLeast(3);
                                }
                                break;
                        case PPC_RELOC_HA16_SECTDIFF:
@@ -2350,6 +2577,9 @@ bool Reader<x86>::addRelocReference(const macho_section<x86::P>* sect, const mac
                                                kind = x86::kPCRel32;
                                                pointerValue += srcAddr + sizeof(uint32_t);
                                        }
+                                       else if ( strcmp(sect->segname(), "__TEXT") == 0 ) {
+                                               kind = x86::kAbsolute32;
+                                       }
                                        else {
                                                kind = x86::kPointer;
                                        }
@@ -2411,7 +2641,10 @@ bool Reader<x86>::addRelocReference(const macho_section<x86::P>* sect, const mac
                                                makeReferenceWithToBase(x86::kPCRel32, srcAddr, betterDstAddr, dstAddr);
                                        }
                                        else {
-                                               makeReferenceWithToBase(x86::kPointer, srcAddr, betterDstAddr, dstAddr);
+                                               if ( strcmp(sect->segname(), "__TEXT") == 0 )
+                                                       makeReferenceWithToBase(x86::kAbsolute32, srcAddr, betterDstAddr, dstAddr);
+                                               else
+                                                       makeReferenceWithToBase(x86::kPointer, srcAddr, betterDstAddr, dstAddr);
                                        }
                                break;
                        case GENERIC_RELOC_SECTDIFF:
@@ -2437,12 +2670,177 @@ bool Reader<x86>::addRelocReference(const macho_section<x86::P>* sect, const mac
        return result;
 }
 
+template <>
+bool Reader<x86_64>::addRelocReference(const macho_section<x86_64::P>* sect, const macho_relocation_info<x86_64::P>* reloc)
+{
+       uint64_t srcAddr;
+       uint64_t dstAddr = 0;
+       uint64_t addend;
+       uint32_t* fixUpPtr;
+       x86_64::ReferenceKinds kind;
+       bool result = false;
+       const macho_nlist<P>* targetSymbol = NULL;
+       const char* targetName = NULL;
+       srcAddr = sect->addr() + reloc->r_address();
+       fixUpPtr = (uint32_t*)((char*)(fHeader) + sect->offset() + reloc->r_address());
+       //fprintf(stderr, "addReloc type=%d\n", reloc->r_type());
+       if ( reloc->r_extern() ) {
+               targetSymbol = &fSymbols[reloc->r_symbolnum()];
+               targetName = &fStrings[targetSymbol->n_strx()];
+       }
+       switch ( reloc->r_type() ) {
+               case X86_64_RELOC_UNSIGNED:
+                       if ( reloc->r_pcrel() )
+                               throw "pcrel and X86_64_RELOC_UNSIGNED not supported";
+                       if ( reloc->r_length() != 3 ) 
+                               throw "length < 3 and X86_64_RELOC_UNSIGNED not supported";
+                       dstAddr = E::get64(*((uint64_t*)fixUpPtr));
+                       if ( reloc->r_extern() ) 
+                               makeReferenceToSymbol(x86_64::kPointer, srcAddr, targetSymbol, dstAddr);
+                       else
+                               makeReference(x86_64::kPointer, srcAddr, dstAddr);
+                       break;
+               case X86_64_RELOC_SIGNED:
+                       if ( ! reloc->r_pcrel() )
+                               throw "not pcrel and X86_64_RELOC_SIGNED not supported";
+                       if ( reloc->r_length() != 2 ) 
+                               throw "length != 2 and X86_64_RELOC_SIGNED not supported";
+                       kind = x86_64::kPCRel32;
+                       dstAddr = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
+                       if ( dstAddr == (uint64_t)(-1) ) {
+                               dstAddr = 0;
+                               kind = x86_64::kPCRel32_1;
+                       }
+                       else if ( dstAddr == (uint64_t)(-2) ) {
+                               dstAddr = 0;
+                               kind = x86_64::kPCRel32_2;
+                       }
+                       else if ( dstAddr == (uint64_t)(-4) ) {
+                               dstAddr = 0;
+                               kind = x86_64::kPCRel32_4;
+                       }
+                       if ( reloc->r_extern() ) 
+                               makeReferenceToSymbol(kind, srcAddr, targetSymbol, dstAddr);
+                       else {
+                               makeReference(kind, srcAddr, srcAddr+4+dstAddr);
+                       }
+                       break;
+               case X86_64_RELOC_BRANCH:
+                       if ( ! reloc->r_pcrel() )
+                               throw "not pcrel and X86_64_RELOC_BRANCH not supported";
+                       if ( reloc->r_length() != 2 ) 
+                               throw "length != 2 and X86_64_RELOC_BRANCH not supported";
+                       dstAddr = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
+                       if ( reloc->r_extern() ) {
+                               if ( isWeakImportSymbol(targetSymbol) )
+                                       makeReferenceToSymbol(x86_64::kBranchPCRel32WeakImport, srcAddr, targetSymbol, dstAddr);
+                               else
+                                       makeReferenceToSymbol(x86_64::kBranchPCRel32, srcAddr, targetSymbol, dstAddr);
+                       }
+                       else {
+                               makeReference(x86_64::kBranchPCRel32, srcAddr, srcAddr+4+dstAddr);
+                       }
+                       break;
+               case X86_64_RELOC_GOT:
+                       if ( ! reloc->r_extern() ) 
+                               throw "not extern and X86_64_RELOC_GOT not supported";
+                       if ( ! reloc->r_pcrel() )
+                               throw "not pcrel and X86_64_RELOC_GOT not supported";
+                       if ( reloc->r_length() != 2 ) 
+                               throw "length != 2 and X86_64_RELOC_GOT not supported";
+                       addend = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
+                       if ( isWeakImportSymbol(targetSymbol) )
+                               makeReferenceToSymbol(x86_64::kPCRel32GOTWeakImport, srcAddr, targetSymbol, addend);
+                       else
+                               makeReferenceToSymbol(x86_64::kPCRel32GOT, srcAddr, targetSymbol, addend);
+                       break;
+               case X86_64_RELOC_GOT_LOAD:
+                       if ( ! reloc->r_extern() ) 
+                               throw "not extern and X86_64_RELOC_GOT_LOAD not supported";
+                       if ( ! reloc->r_pcrel() )
+                               throw "not pcrel and X86_64_RELOC_GOT_LOAD not supported";
+                       if ( reloc->r_length() != 2 ) 
+                               throw "length != 2 and X86_64_RELOC_GOT_LOAD not supported";
+                       addend = (int64_t)((int32_t)(E::get32(*fixUpPtr)));
+                       if ( isWeakImportSymbol(targetSymbol) )
+                               makeReferenceToSymbol(x86_64::kPCRel32GOTLoadWeakImport, srcAddr, targetSymbol, addend);
+                       else
+                               makeReferenceToSymbol(x86_64::kPCRel32GOTLoad, srcAddr, targetSymbol, addend);
+                       break;
+               case X86_64_RELOC_SUBTRACTOR:
+                       if ( reloc->r_pcrel() )
+                               throw "X86_64_RELOC_SUBTRACTOR cannot be pc-relative";
+                       if ( reloc->r_length() < 2 )
+                               throw "X86_64_RELOC_SUBTRACTOR must have r_length of 2 or 3";
+                       if ( !reloc->r_extern() )
+                               throw "X86_64_RELOC_SUBTRACTOR must have r_extern=1";
+                       const macho_relocation_info<x86_64::P>* nextReloc = &reloc[1];
+                       if ( nextReloc->r_type() != X86_64_RELOC_UNSIGNED )
+                               throw "X86_64_RELOC_SUBTRACTOR must be followed by X86_64_RELOC_UNSIGNED";
+                       result = true;
+                       if ( nextReloc->r_pcrel() )
+                               throw "X86_64_RELOC_UNSIGNED following a X86_64_RELOC_SUBTRACTOR cannot be pc-relative";
+                       if ( nextReloc->r_length() != reloc->r_length() )
+                               throw "X86_64_RELOC_UNSIGNED following a X86_64_RELOC_SUBTRACTOR must have same r_length";
+                       Reference<x86_64>* ref;
+                       bool negativeAddend;
+                       if ( reloc->r_length() == 2 ) {
+                               kind = x86_64::kPointerDiff32;
+                               dstAddr = E::get32(*fixUpPtr); // addend is in content
+                               negativeAddend = ((dstAddr & 0x80000000) != 0);
+                       }
+                       else {
+                               kind = x86_64::kPointerDiff;
+                               dstAddr = E::get64(*((uint64_t*)fixUpPtr)); // addend is in content
+                               negativeAddend = ((dstAddr & 0x8000000000000000ULL) != 0);
+                       }
+                       ObjectFile::Atom* inAtom = this->findAtomAndOffset(srcAddr).atom;
+                       // create reference with "to" target
+                       if ( nextReloc->r_extern() ) {
+                               const macho_nlist<P>* targetSymbol = &fSymbols[nextReloc->r_symbolnum()];
+                               const char* targetName = &fStrings[targetSymbol->n_strx()];
+                               ref = makeReferenceToSymbol(kind, srcAddr, targetSymbol, 0);
+                               // if "to" is in this atom, change by-name to a direct reference
+                               if ( strcmp(targetName, inAtom->getName()) == 0 )
+                                       ref->setTarget(*inAtom, 0);
+                       }
+                       else {
+                               ref = makeReference(kind, srcAddr, dstAddr);
+                       }
+                       // add in "from" target
+                       if ( reloc->r_extern() ) {
+                               const macho_nlist<P>* targetFromSymbol = &fSymbols[reloc->r_symbolnum()];
+                               const char* fromTargetName = &fStrings[targetFromSymbol->n_strx()];
+                               if ( (targetFromSymbol->n_type() & N_EXT) == 0 ) {
+                                       // from target is translation unit scoped, so use a direct reference
+                                       ref->setFromTarget(*(findAtomAndOffset(targetSymbol->n_value()).atom));
+                               }
+                               else if ( strcmp(fromTargetName, inAtom->getName()) == 0 ) {
+                                       // if "from" is in this atom, change by-name to a direct reference
+                                       ref->setFromTarget(*inAtom);
+                               }
+                               else {
+                                       // some non-static other atom
+                                       ref->setFromTargetName(fromTargetName);
+                               }
+                       }
+                       // addend goes in from side iff negative
+                       if ( negativeAddend )
+                               ref->setFromTargetOffset(-dstAddr);
+                       else
+                               ref->setToTargetOffset(dstAddr);
+                       break;
+               default:
+                       fprintf(stderr, "unknown relocation type %d\n", reloc->r_type());
+       }
+       return result;
+}
 
 
 template <>
 const char* Reference<x86>::getDescription() const
 {
-       static char temp[1024];
+       static char temp[2048];
        switch( fKind ) {
                case x86::kNoFixUp:
                        sprintf(temp, "reference to ");
@@ -2473,6 +2871,9 @@ const char* Reference<x86>::getDescription() const
                case x86::kPCRel32:
                        sprintf(temp, "offset 0x%04X, rel32 reference to ", fFixUpOffsetInSrc);
                        break;
+               case x86::kAbsolute32:
+                       sprintf(temp, "offset 0x%04X, absolute32 reference to ", fFixUpOffsetInSrc);
+                       break;
        }
        // always quote by-name references
        if ( fToTargetName != NULL ) {
@@ -2496,7 +2897,7 @@ const char* Reference<x86>::getDescription() const
 template <>
 const char* Reference<ppc>::getDescription() const
 {
-       static char temp[1024];
+       static char temp[2048];
        switch( fKind ) {
                case ppc::kNoFixUp:
                        sprintf(temp, "reference to ");
@@ -2573,7 +2974,7 @@ const char* Reference<ppc>::getDescription() const
 template <>
 const char* Reference<ppc64>::getDescription() const
 {
-       static char temp[1024];
+       static char temp[2048];
        switch( fKind ) {
                case ppc64::kNoFixUp:
                        sprintf(temp, "reference to ");
@@ -2649,12 +3050,90 @@ const char* Reference<ppc64>::getDescription() const
                strcat(temp, "NULL target");
        }
        if ( fToTarget.offset != 0 )
-               sprintf(&temp[strlen(temp)], " plus 0x%08X", fToTarget.offset);
+               sprintf(&temp[strlen(temp)], " plus 0x%llX", this->getTargetOffset());
 
        return temp;
 }
 
 
+template <>
+const char* Reference<x86_64>::getDescription() const
+{
+       static char temp[2048];
+       switch( fKind ) {
+               case x86_64::kNoFixUp:
+                       sprintf(temp, "reference to ");
+                       break;
+               case x86_64::kFollowOn:
+                       sprintf(temp, "followed by ");
+                       break;
+               case x86_64::kPointerWeakImport:
+                       sprintf(temp, "offset 0x%04llX, weak import pointer to ", fFixUpOffsetInSrc);
+                       break;
+               case x86_64::kPointer:
+                       sprintf(temp, "offset 0x%04llX, pointer to ", fFixUpOffsetInSrc);
+                       break;
+               case x86_64::kPointerDiff32:
+               case x86_64::kPointerDiff:
+                       {
+                       // by-name references have quoted names
+                       const char* targetQuotes = (&(this->getTarget()) == NULL) ? "\"" : "";
+                       const char* fromQuotes = (&(this->getFromTarget()) == NULL) ? "\"" : "";
+                       const char* size = (fKind == x86_64::kPointerDiff32) ? "32-bit" : "64-bit";
+                       sprintf(temp, "offset 0x%04llX, %s pointer difference: (&%s%s%s + 0x%08X) - (&%s%s%s + 0x%08X)",
+                               fFixUpOffsetInSrc, size, targetQuotes, this->getTargetName(), targetQuotes, fToTarget.offset,
+                                                          fromQuotes, this->getFromTargetName(), fromQuotes, fFromTarget.offset );
+                       return temp;
+                       }
+                       break;
+               case x86_64::kPCRel32:
+                       sprintf(temp, "offset 0x%04llX, rel32 reference to ", fFixUpOffsetInSrc);
+                       break;
+               case x86_64::kPCRel32_1:
+                       sprintf(temp, "offset 0x%04llX, rel32-1 reference to ", fFixUpOffsetInSrc);
+                       break;
+               case x86_64::kPCRel32_2:
+                       sprintf(temp, "offset 0x%04llX, rel32-2 reference to ", fFixUpOffsetInSrc);
+                       break;
+               case x86_64::kPCRel32_4:
+                       sprintf(temp, "offset 0x%04llX, rel32-4 reference to ", fFixUpOffsetInSrc);
+                       break;
+               case x86_64::kBranchPCRel32:
+                       sprintf(temp, "offset 0x%04llX, branch rel32 reference to ", fFixUpOffsetInSrc);
+                       break;
+               case x86_64::kBranchPCRel32WeakImport:
+                       sprintf(temp, "offset 0x%04llX, branch rel32 reference to weak imported ", fFixUpOffsetInSrc);
+                       break;
+               case x86_64::kPCRel32GOT:
+                       sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for ", fFixUpOffsetInSrc);
+                       break;
+               case x86_64::kPCRel32GOTWeakImport:
+                       sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for weak imported ", fFixUpOffsetInSrc);
+                       break;
+               case x86_64::kPCRel32GOTLoad:
+                       sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for ", fFixUpOffsetInSrc);
+                       break;
+               case x86_64::kPCRel32GOTLoadWeakImport:
+                       sprintf(temp, "offset 0x%04llX, rel32 reference to GOT entry for weak imported ", fFixUpOffsetInSrc);
+                       break;
+       }
+       // always quote by-name references
+       if ( fToTargetName != NULL ) {
+               strcat(temp, "\"");
+               strcat(temp, fToTargetName);
+               strcat(temp, "\"");
+       }
+       else if ( fToTarget.atom != NULL ) {
+               strcat(temp, fToTarget.atom->getDisplayName());
+       }
+       else {
+               strcat(temp, "NULL target");
+       }
+       if ( fToTarget.offset != 0 )
+               sprintf(&temp[strlen(temp)], " plus 0x%llX", this->getTargetOffset());
+
+       return temp;
+}
 
 
 }; // namespace relocatable
index 30aa24b3081cccd475f09cb1ce1ae931ad41aadd..70798a6912f23492d886e7667b4fdd1158a8888a 100644 (file)
@@ -189,6 +189,7 @@ private:
        void                                            adjustLinkEditSections();
        void                                            buildObjectFileFixups();
        void                                            buildExecutableFixups();
+       uint64_t                                        relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const;
        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;
@@ -207,7 +208,9 @@ private:
        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);
+       bool                                            illegalRelocInFinalLinkedImage(const ObjectFile::Reference&, bool slideable);
+       bool                                            mightNeedPadSegment();
+       void                                            scanForAbsoluteReferences();
 
 
        struct DirectLibrary {
@@ -253,6 +256,7 @@ private:
        class UUIDLoadCommandAtom<A>*                               fUUIDAtom;
        std::vector<class ObjectFile::Atom*>                    fWriterSynthesizedAtoms;
        std::vector<SegmentInfo*>                                               fSegmentInfos;
+       class SegmentInfo*                                                              fPadSegmentInfo;
        class ObjectFile::Atom*                                                 fEntryPoint;
        class ObjectFile::Atom*                                                 fDyldHelper;
        std::vector<DirectLibrary>                                              fDirectLibraries;
@@ -266,6 +270,7 @@ private:
        class SymbolTableLinkEditAtom<A>*                               fSymbolTableAtom;
        class IndirectTableLinkEditAtom<A>*                             fIndirectTableAtom;
        class StringsLinkEditAtom<A>*                                   fStringsAtom;
+       class PageZeroAtom<A>*                                                  fPageZeroAtom;
        macho_nlist<P>*                                                                 fSymbolTable;
        std::vector<macho_relocation_info<P> >                  fSectionRelocs;
        std::vector<macho_relocation_info<P> >                  fInternalRelocs;
@@ -290,7 +295,9 @@ private:
        bool                                                                                    fHasWeakExports;
        bool                                                                                    fReferencesWeakImports;
        bool                                                                                    fSeenFollowOnReferences;
+       bool                                                                                    fWritableSegmentPastFirst4GB;
        std::map<const ObjectFile::Atom*,bool>                  fWeakImportMap;
+       SegmentInfo*                                                                    fFirstWritableSegment;
 };
 
 
@@ -311,6 +318,7 @@ public:
        static Segment                                                          fgStackSegment;
        static Segment                                                          fgImportSegment;
        static Segment                                                          fgDataSegment;
+       
 private:
        const char*                                     fName;
        const bool                                      fReadable;
@@ -332,7 +340,7 @@ 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(); }
+                                                                                       WriterAtom(Writer<A>& writer, Segment& segment) : fWriter(writer), fSegment(segment) { }
 
        virtual ObjectFile::Reader*                             getFile() const                                 { return &fWriter; }
        virtual bool                                                    getTranslationUnitSource(const char** dir, const char** name) const { return false; }
@@ -341,6 +349,7 @@ public:
        virtual Scope                                                   getScope() const                                { return ObjectFile::Atom::scopeTranslationUnit; }
        virtual DefinitionKind                                  getDefinitionKind() const               { return kRegularDefinition; }
        virtual SymbolTableInclusion                    getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
+       virtual bool                                                    dontDeadStrip() const                   { return true; }
        virtual bool                                                    isZeroFill() const                              { return false; }
        virtual std::vector<ObjectFile::Reference*>&  getReferences() const             { return fgEmptyReferenceList; }
        virtual bool                                                    mustRemainInSection() const             { return true; }
@@ -371,17 +380,21 @@ template <typename A>
 class PageZeroAtom : public WriterAtom<A>
 {
 public:
-                                                                                       PageZeroAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgPageZeroSegment) {}
+                                                                                       PageZeroAtom(Writer<A>& writer) : WriterAtom<A>(writer, Segment::fgPageZeroSegment),
+                                                                                                                                                       fSize(fWriter.fOptions.zeroPageSize()) {}
        virtual const char*                                             getDisplayName() const  { return "page zero content"; }
        virtual bool                                                    isZeroFill() const              { return true; }
-       virtual uint64_t                                                getSize() const                 { return fWriter.fOptions.zeroPageSize(); }
+       virtual uint64_t                                                getSize() const                 { return fSize; }
        virtual const char*                                             getSectionName() const  { return "._zeropage"; }
        virtual uint8_t                                                 getAlignment() const    { return 12; }
+       void                                                                    setSize(uint64_t size)  { fSize = size; }
 private:
        using WriterAtom<A>::fWriter;
        typedef typename A::P                                   P;
+       uint64_t                                                                fSize;
 };
 
+
 template <typename A>
 class DsoHandleAtom : public WriterAtom<A>
 {
@@ -457,7 +470,6 @@ public:
        void                                                                    computeSize();
        void                                                                    setup();
        unsigned int                                                    commandCount()                  { return fCommandCount; }
-       void                                                                    assignFileOffsets();
 private:
        using WriterAtom<A>::fWriter;
        typedef typename A::P                                   P;
@@ -465,6 +477,7 @@ private:
        uint32_t                                                                fSize;
 };
 
+
 template <typename A>
 class SymbolTableLoadCommandsAtom : public LoadCommandAtom<A>
 {
@@ -858,6 +871,26 @@ private:
        std::vector<ObjectFile::Reference*>             fReferences;
 };
 
+template <typename A>
+class StubHelperAtom : public WriterAtom<A>
+{
+public:
+                                                                                       StubHelperAtom(Writer<A>& writer, ObjectFile::Atom& target, ObjectFile::Atom& lazyPointer);
+       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 "__stub_helper"; }
+       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);
+       using WriterAtom<A>::fWriter;
+       const char*                                                             fName;
+       ObjectFile::Atom&                                               fTarget;
+       std::vector<ObjectFile::Reference*>             fReferences;
+};
 
 template <typename A>
 class LazyPointerAtom : public WriterAtom<A>
@@ -956,9 +989,9 @@ struct ExportSorter
 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),
+         fLoadCommandsSegment(NULL), fPadSegmentInfo(NULL), fPageZeroAtom(NULL), fLargestAtomSize(1), 
          fEmitVirtualSections(false), fHasWeakExports(false), fReferencesWeakImports(false),
-         fSeenFollowOnReferences(false)
+         fSeenFollowOnReferences(false), fWritableSegmentPastFirst4GB(false), fFirstWritableSegment(NULL)
 {
        int permissions = 0777;
        if ( fOptions.outputKind() == Options::kObjectFile )
@@ -975,7 +1008,7 @@ Writer<A>::Writer(const char* path, Options& options, std::vector<ExecutableFile
        switch ( fOptions.outputKind() ) {
                case Options::kDynamicExecutable:
                case Options::kStaticExecutable:
-                       fWriterSynthesizedAtoms.push_back(new PageZeroAtom<A>(*this));
+                       fWriterSynthesizedAtoms.push_back(fPageZeroAtom = new PageZeroAtom<A>(*this));
                        if ( fOptions.outputKind() == Options::kDynamicExecutable )
                                fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
                        fWriterSynthesizedAtoms.push_back(new MachHeaderAtom<A>(*this));
@@ -1045,7 +1078,10 @@ Writer<A>::Writer(const char* path, Options& options, std::vector<ExecutableFile
                                const unsigned int libCount = dynamicLibraries.size();
                                for (unsigned int i=0; i < libCount; ++i) {
                                        ExecutableFile::DyLibUsed& dylibInfo = dynamicLibraries[i];
-                                       if ( dylibInfo.indirect ) {
+                                       if ( dylibInfo.options.fBundleLoader ) {
+                                               fLibraryToOrdinal[dylibInfo.reader] = EXECUTABLE_ORDINAL;
+                                       }
+                                       else if ( dylibInfo.indirect ) {
                                                // find ordinal of direct reader
                                                if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace ) {
                                                        bool found = false;
@@ -1069,7 +1105,7 @@ Writer<A>::Writer(const char* path, Options& options, std::vector<ExecutableFile
                                                        dylibInstallPath = dylibInfo.options.fInstallPathOverride;
                                                for (unsigned int seenLib=0; seenLib < i; ++seenLib) {
                                                        ExecutableFile::DyLibUsed& seenDylibInfo = dynamicLibraries[seenLib];
-                                                       if ( !seenDylibInfo.indirect ) {
+                                                       if ( !seenDylibInfo.indirect && !seenDylibInfo.options.fBundleLoader ) {
                                                                const char* seenDylibInstallPath = seenDylibInfo.reader->getInstallPath();
                                                                if ( seenDylibInfo.options.fInstallPathOverride != NULL )
                                                                        seenDylibInstallPath = dylibInfo.options.fInstallPathOverride;
@@ -1148,6 +1184,11 @@ Writer<A>::~Writer()
 }
 
 
+// for ppc64, -mdynamic-no-pic only works in low 2GB, so we might need to split the zeropage into two segments
+template <>bool Writer<ppc64>::mightNeedPadSegment() { return (fOptions.zeroPageSize() >= 0x80000000ULL); }
+template <typename A> bool Writer<A>::mightNeedPadSegment() { return false; }
+
+
 template <typename A>
 ObjectFile::Atom* Writer<A>::getUndefinedProxyAtom(const char* name)
 {
@@ -1189,31 +1230,41 @@ uint64_t Writer<A>::write(std::vector<class ObjectFile::Atom*>& atoms,
        fEntryPoint = entryPointAtom;
        fDyldHelper = dyldHelperAtom;
 
-       // Set for create UUID
-       if (createUUID)
-               fUUIDAtom->emit();
+       try {
+               // Set for create UUID
+               if (createUUID)
+                       fUUIDAtom->emit();
 
-       // create inter-library stubs
-       synthesizeStubs();
+               // check for mdynamic-no-pic codegen which force code into low 4GB
+               scanForAbsoluteReferences();
 
-       // create SegmentInfo and SectionInfo objects and assign all atoms to a section
-       partitionIntoSections();
+               // create inter-library stubs
+               synthesizeStubs();
 
-       // segment load command can now be sized and padding can be set
-       adjustLoadCommandsAndPadding();
+               // create SegmentInfo and SectionInfo objects and assign all atoms to a section
+               partitionIntoSections();
 
-       // assign each section a file offset
-       assignFileOffsets();
+               // segment load command can now be sized and padding can be set
+               adjustLoadCommandsAndPadding();
 
-       // if need to add branch islands, reassign file offsets
-       if ( addBranchIslands() )
+               // assign each section a file offset
                assignFileOffsets();
 
-       // build symbol table and relocations
-       buildLinkEdit();
+               // if need to add branch islands, reassign file offsets
+               if ( addBranchIslands() )
+                       assignFileOffsets();
 
-       // write everything
-       return writeAtoms();
+               // build symbol table and relocations
+               buildLinkEdit();
+
+               // write everything
+               return writeAtoms();
+       } catch (...) {
+               // clean up if any errors
+               close(fFileDescriptor);
+               (void)unlink(fFilePath);
+               throw;
+       }
 }
 
 template <typename A>
@@ -1239,12 +1290,17 @@ 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);
+       if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAsAbsolute ) {
+               entry->set_n_type(N_EXT | N_ABS);
        }
-
+       else {
+               entry->set_n_type(N_EXT | N_SECT);
+               if ( (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit) && (fOptions.outputKind() == Options::kObjectFile) ) {
+                       if ( fOptions.keepPrivateExterns() )
+                               entry->set_n_type(N_EXT | N_SECT | N_PEXT);
+               }
+       }
+       
        // set n_sect (section number of implementation )
        uint8_t sectionIndex = atom->getSection()->getIndex();
        entry->set_n_sect(sectionIndex);
@@ -1416,7 +1472,7 @@ void Writer<A>::collectExportedAndImportedAndLocalAtoms()
                                        fImportedAtoms.push_back(atom);
                                        break;
                                case ObjectFile::Atom::kTentativeDefinition:
-                                       if ( fOptions.outputKind() == Options::kObjectFile ) {
+                                       if ( (fOptions.outputKind() == Options::kObjectFile) && !fOptions.makeTentativeDefinitionsReal() ) {
                                                fImportedAtoms.push_back(atom);
                                                break;
                                        }
@@ -1445,7 +1501,7 @@ uint64_t Writer<A>::valueForStab(const ObjectFile::Reader::Stab& stab)
 {
        switch ( stab.type ) {
                case N_FUN:
-                       if ( stab.other == 0 ) {
+                       if ( (stab.string == NULL) || (strlen(stab.string) == 0) ) {
                                // end of function N_FUN has size
                                return stab.atom->getSize();
                        }
@@ -1470,7 +1526,20 @@ uint64_t Writer<A>::valueForStab(const ObjectFile::Reader::Stab& stab)
                case N_ENSYM:
                        return stab.atom->getSize();
                case N_SO:
-                       return 0;
+                       if ( stab.atom == NULL ) {
+                               return 0;
+                       }
+                       else {
+                               if ( (stab.string == NULL) || (strlen(stab.string) == 0) ) {
+                                       // end of translation unit N_SO has address of end of last atom
+                                       return getAtomLoadAddress(stab.atom) + stab.atom->getSize();
+                               }
+                               else {
+                                       // start of translation unit N_SO has address of end of first atom
+                                       return getAtomLoadAddress(stab.atom);
+                               }
+                       }
+                       break;
                default:
                        return stab.value;
        }
@@ -1505,7 +1574,10 @@ uint32_t Writer<A>::stringOffsetForStab(const ObjectFile::Reader::Stab& stab)
 template <typename A>
 uint8_t Writer<A>::sectionIndexForStab(const ObjectFile::Reader::Stab& stab)
 {
-       if ( stab.atom != NULL ) 
+       // in FUN stabs, n_sect field is 0 for start FUN and 1 for end FUN
+       if ( stab.type == N_FUN )
+               return stab.other;
+       else if ( stab.atom != NULL ) 
                return stab.atom->getSection()->getIndex();
        else
                return stab.other;
@@ -1571,6 +1643,104 @@ void Writer<A>::buildFixups()
        }
 }
 
+template <>
+uint32_t Writer<x86_64>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
+{
+       ObjectFile::Atom& target = ref->getTarget();
+       bool external = (target.getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn);
+       uint32_t symbolIndex = external ? this->symbolIndex(target) : target.getSection()->getIndex();
+       uint32_t address = atom->getSectionOffset()+ref->getFixUpOffset();
+       macho_relocation_info<P> reloc1;
+       macho_relocation_info<P> reloc2;
+       x86_64::ReferenceKinds kind = (x86_64::ReferenceKinds)ref->getKind();
+
+       switch ( kind ) {
+               case x86_64::kNoFixUp:
+               case x86_64::kFollowOn:
+                       return 0;
+
+               case x86_64::kPointer:
+               case x86_64::kPointerWeakImport:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolIndex);
+                       reloc1.set_r_pcrel(false);
+                       reloc1.set_r_length(3);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
+                       fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
+                       return 1;
+
+               case x86_64::kPointerDiff32:
+               case x86_64::kPointerDiff:      
+                       {
+                       ObjectFile::Atom& fromTarget = ref->getFromTarget();
+                       bool fromExternal = (fromTarget.getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn);
+                       uint32_t fromSymbolIndex = fromExternal ? this->symbolIndex(fromTarget) : fromTarget.getSection()->getIndex();
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolIndex);
+                       reloc1.set_r_pcrel(false);
+                       reloc1.set_r_length(kind==x86_64::kPointerDiff32 ? 2 : 3);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(X86_64_RELOC_UNSIGNED);
+                       reloc2.set_r_address(address);
+                       reloc2.set_r_symbolnum(fromSymbolIndex);
+                       reloc2.set_r_pcrel(false);
+                       reloc2.set_r_length(kind==x86_64::kPointerDiff32 ? 2 : 3);
+                       reloc2.set_r_extern(fromExternal);
+                       reloc2.set_r_type(X86_64_RELOC_SUBTRACTOR);
+                       fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
+                       fSectionRelocs.insert(fSectionRelocs.begin(), reloc2);
+                       return 2;
+                       }
+
+               case x86_64::kBranchPCRel32:
+               case x86_64::kBranchPCRel32WeakImport:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolIndex);
+                       reloc1.set_r_pcrel(true);
+                       reloc1.set_r_length(2);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(X86_64_RELOC_BRANCH);
+                       fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
+                       return 1;
+
+               case x86_64::kPCRel32:
+               case x86_64::kPCRel32_1:
+               case x86_64::kPCRel32_2:
+               case x86_64::kPCRel32_4:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolIndex);
+                       reloc1.set_r_pcrel(true);
+                       reloc1.set_r_length(2);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(X86_64_RELOC_SIGNED);
+                       fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
+                       return 1;
+
+               case x86_64::kPCRel32GOT:
+               case x86_64::kPCRel32GOTWeakImport:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolIndex);
+                       reloc1.set_r_pcrel(true);
+                       reloc1.set_r_length(2);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(X86_64_RELOC_GOT);
+                       fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
+                       return 1;
+
+               case x86_64::kPCRel32GOTLoad:
+               case x86_64::kPCRel32GOTLoadWeakImport:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolIndex);
+                       reloc1.set_r_pcrel(true);
+                       reloc1.set_r_length(2);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(X86_64_RELOC_GOT_LOAD);
+                       fSectionRelocs.insert(fSectionRelocs.begin(), reloc1);
+                       return 1;
+       }
+       return 0;
+}
 
 template <>
 uint32_t Writer<x86>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Reference* ref)
@@ -1606,6 +1776,7 @@ uint32_t Writer<x86>::addObjectRelocs(ObjectFile::Atom* atom, ObjectFile::Refere
 
                case x86::kPointer:
                case x86::kPointerWeakImport:
+               case x86::kAbsolute32:
                        if ( !isExtern && (ref->getTargetOffset() != 0) ) {
                                // use scattered reloc is target offset is non-zero
                                sreloc1->set_r_scattered(true);
@@ -2031,9 +2202,8 @@ void Writer<A>::buildObjectFileFixups()
                                                                //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() )
+                                                               // only use INDIRECT_SYMBOL_LOCAL in non-lazy-pointers for atoms that won't be in symbol table
+                                                               if ( curSection->fAllNonLazyPointers && (ref->getTarget().getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn) )
                                                                        undefinedSymbolIndex = INDIRECT_SYMBOL_LOCAL;
                                                                else
                                                                        undefinedSymbolIndex = this->symbolIndex(ref->getTarget());
@@ -2067,7 +2237,7 @@ void Writer<A>::buildObjectFileFixups()
                                                                relocIndex += this->addObjectRelocs(atom, ref);
                                                        }
                                                }
-                                               else {
+                                               else if ( ref->getKind() != A::kNoFixUp ) {
                                                        relocIndex += this->addObjectRelocs(atom, ref);
                                                }
                                        }
@@ -2091,9 +2261,9 @@ void Writer<A>::buildObjectFileFixups()
 }
 
 template <>
-bool Writer<ppc>::illegalRelocInFinalLinkedImage(uint8_t kind, bool slideable)
+bool Writer<ppc>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref, bool slideable)
 {
-       switch ( kind ) {
+       switch ( ref.getKind() ) {
                case ppc::kAbsLow16:
                case ppc::kAbsLow14:
                case ppc::kAbsHigh16:
@@ -2106,9 +2276,9 @@ bool Writer<ppc>::illegalRelocInFinalLinkedImage(uint8_t kind, bool slideable)
 
 
 template <>
-bool Writer<ppc64>::illegalRelocInFinalLinkedImage(uint8_t kind, bool slideable)
+bool Writer<ppc64>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref, bool slideable)
 {
-       switch ( kind ) {
+       switch ( ref.getKind() ) {
                case ppc::kAbsLow16:
                case ppc::kAbsLow14:
                case ppc::kAbsHigh16:
@@ -2120,11 +2290,31 @@ bool Writer<ppc64>::illegalRelocInFinalLinkedImage(uint8_t kind, bool slideable)
 }
 
 template <>
-bool Writer<x86>::illegalRelocInFinalLinkedImage(uint8_t kind, bool slideable)
-{
+bool Writer<x86>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref, bool slideable)
+{
+       if ( ref.getKind() == x86::kAbsolute32 ) {
+               switch ( ref.getTarget().getDefinitionKind() ) {
+                       case ObjectFile::Atom::kTentativeDefinition:
+                       case ObjectFile::Atom::kRegularDefinition:
+                               // illegal in dylibs/bundles, until we support TEXT relocs 
+                               return slideable;
+                       case ObjectFile::Atom::kWeakDefinition:
+                               // illegal if an exported weak symbol, until we support TEXT relocs
+                               return this->shouldExport(ref.getTarget());
+                       case ObjectFile::Atom::kExternalDefinition:
+                       case ObjectFile::Atom::kExternalWeakDefinition:
+                               // illegal until we support TEXT relocs
+                               return true;
+               }
+       }
        return false;
 }
 
+template <>
+bool Writer<x86_64>::illegalRelocInFinalLinkedImage(const ObjectFile::Reference& ref, bool slideable)
+{
+       return false;
+}
 
 
 template <typename A>
@@ -2161,6 +2351,64 @@ typename Writer<A>::RelocKind Writer<A>::relocationNeededInFinalLinkedImage(cons
        return kRelocNone;
 }
 
+template <typename A>
+uint64_t Writer<A>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom) const
+{
+       // for 32-bit architectures, the r_address field in relocs
+       // for final linked images is the offset from the base address
+       uint64_t result = address - fOptions.baseAddress();
+       if ( result > 0x7FFFFFFF ) {
+               throwf("image too large: address can't fit in 31-bit r_address field in %s from %s",
+                       atom->getDisplayName(), atom->getFile()->getPath());
+       }
+       return result;
+}
+
+template <>
+uint64_t Writer<x86_64>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom)  const
+{
+       // for x86_64, the r_address field in relocs for final linked images 
+       // is the offset from the start address of the first writable segment
+       uint64_t result = address - fFirstWritableSegment->fBaseAddress;
+       if ( result > 0xFFFFFFFF ) {
+               throwf("image too large: address can't fit in 32-bit r_address field in %s from %s",
+                       atom->getDisplayName(), atom->getFile()->getPath());
+       }
+       return result;
+}
+
+template <>
+uint64_t Writer<ppc64>::relocAddressInFinalLinkedImage(uint64_t address, const ObjectFile::Atom* atom)  const
+{
+       // for ppc64, the Mac OS X 10.4 dyld assumes r_address is always the offset from the base address.  
+       // the 10.5 dyld, iterprets the r_address as:
+       //   1) an offset from the base address, iff there are no writable segments with a address > 4GB from base address, otherwise
+       //   2) an offset from the base address of the first writable segment
+       // For dyld, r_address is always the offset from the base address
+       uint64_t result;
+       bool badFor10_4 = false;
+       if ( fWritableSegmentPastFirst4GB ) {
+               if ( fOptions.macosxVersionMin() < Options::k10_5 )
+                       badFor10_4 = true;
+               result = address - fFirstWritableSegment->fBaseAddress;
+               if ( result > 0xFFFFFFFF ) {
+                       throwf("image too large: address can't fit in 32-bit r_address field in %s from %s",
+                               atom->getDisplayName(), atom->getFile()->getPath());
+               }
+       }
+       else {
+               result = address - fOptions.baseAddress();
+               if ( (fOptions.macosxVersionMin() < Options::k10_5) && (result > 0x7FFFFFFF) )
+                       badFor10_4 = true;
+       }
+       if ( badFor10_4 ) {
+                       throwf("image or pagezero_size too large for Mac OS X 10.4: address can't fit in 31-bit r_address field for %s from %s",
+                               atom->getDisplayName(), atom->getFile()->getPath());
+       }
+       return result;
+}
+
+
 template <typename A>
 void Writer<A>::buildExecutableFixups()
 {
@@ -2212,7 +2460,7 @@ void Writer<A>::buildExecutableFixups()
                                                                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_address(relocAddressInFinalLinkedImage(atom->getAddress(), atom));
                                                                pblaReloc.set_r_symbolnum(sectionNum);
                                                                pblaReloc.set_r_pcrel(false);
                                                                pblaReloc.set_r_length();
@@ -2223,7 +2471,8 @@ void Writer<A>::buildExecutableFixups()
                                                }
                                                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());
+                                                               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:
@@ -2237,7 +2486,7 @@ void Writer<A>::buildExecutableFixups()
                                                                                // 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_address(this->relocAddressInFinalLinkedImage(atom->getAddress() + ref->getFixUpOffset(), atom));
                                                                                internalReloc.set_r_symbolnum(sectionNum);
                                                                                internalReloc.set_r_pcrel(false);
                                                                                internalReloc.set_r_length();
@@ -2249,7 +2498,7 @@ void Writer<A>::buildExecutableFixups()
                                                                case kRelocExternal:
                                                                        {
                                                                                macho_relocation_info<P> externalReloc;
-                                                                               externalReloc.set_r_address(atom->getAddress()+ref->getFixUpOffset()-fOptions.baseAddress());
+                                                                               externalReloc.set_r_address(this->relocAddressInFinalLinkedImage(atom->getAddress() + ref->getFixUpOffset(), atom));
                                                                                externalReloc.set_r_symbolnum(this->symbolIndex(ref->getTarget()));
                                                                                externalReloc.set_r_pcrel(false);
                                                                                externalReloc.set_r_length();
@@ -2260,7 +2509,7 @@ void Writer<A>::buildExecutableFixups()
                                                                        break;
                                                        }
                                                }
-                                               else if ( this->illegalRelocInFinalLinkedImage(ref->getKind(), slideable) ) {
+                                               else if ( this->illegalRelocInFinalLinkedImage(*ref, slideable) ) {
                                                        throwf("absolute addressing (perhaps -mdynamic-no-pic) used in %s from %s not allowed in slidable image", atom->getDisplayName(), atom->getFile()->getPath());
                                                }
                                        }
@@ -2307,6 +2556,13 @@ void Writer<x86>::writeNoOps(uint32_t from, uint32_t to)
                ::pwrite(fFileDescriptor, &x86Nop, 1, p);
 }
 
+template <>
+void Writer<x86_64>::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()
@@ -2380,7 +2636,8 @@ uint64_t Writer<A>::writeAtoms()
                                                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());
+                                               //fprintf(stderr, "writing 0x%08X -> 0x%08X (addr=0x%llX, size=0x%llX), atom %s from %s\n", 
+                                               //      offset, end, atom->getAddress(), atom->getSize(), atom->getDisplayName(), atom->getFile()->getPath());
                                                // write out
                                                ::pwrite(fFileDescriptor, buffer, atom->getSize(), offset);
                                        }
@@ -2389,6 +2646,7 @@ uint64_t Writer<A>::writeAtoms()
                }
        }
        delete [] buffer;
+       close(fFileDescriptor);
        return end;
 }
 
@@ -2397,6 +2655,8 @@ 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()];
+       const int64_t bl_twoGigLimit = 0x7FFFFFFF;
+       int64_t displacement;
        switch ( (x86::ReferenceKinds)(ref->getKind()) ) {
                case x86::kNoFixUp:
                case x86::kFollowOn:
@@ -2405,12 +2665,12 @@ void Writer<x86>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const Ob
                case x86::kPointerWeakImport:
                case x86::kPointer:
                        {
-                               if ( ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kRegularDefinition ) {
+                               if ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal ) {
                                        // external realocation ==> pointer contains addend
                                        LittleEndian::set32(*fixUp, ref->getTargetOffset());
                                }
                                else {
-                                       // internal relocation => pointer contains target address
+                                       // 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());
                                }
@@ -2422,7 +2682,7 @@ void Writer<x86>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const Ob
                        break;
                case x86::kPCRel32WeakImport:
                case x86::kPCRel32:
-                       int64_t displacement = 0;
+                       displacement = 0;
                        switch ( ref->getTarget().getDefinitionKind() ) {
                                case ObjectFile::Atom::kRegularDefinition:
                                case ObjectFile::Atom::kWeakDefinition:
@@ -2435,13 +2695,27 @@ void Writer<x86>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const Ob
                                        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;
+               case x86::kAbsolute32:
+                       switch ( ref->getTarget().getDefinitionKind() ) {
+                               case ObjectFile::Atom::kRegularDefinition:
+                               case ObjectFile::Atom::kWeakDefinition:
+                               case ObjectFile::Atom::kTentativeDefinition:
+                                       // pointer contains target address
+                                       LittleEndian::set32(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
+                                       break;
+                               case ObjectFile::Atom::kExternalDefinition:
+                               case ObjectFile::Atom::kExternalWeakDefinition:
+                                       // external realocation ==> pointer contains addend
+                                       LittleEndian::set32(*fixUp, ref->getTargetOffset());
+                                       break;
+                       }
+                       break;
        }
 }
 
@@ -2451,12 +2725,14 @@ void Writer<x86>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, co
        uint32_t* fixUp = (uint32_t*)&buffer[ref->getFixUpOffset()];
        bool isExternal = ( (ref->getTarget().getDefinitionKind() != ObjectFile::Atom::kRegularDefinition)
                                                && shouldExport(ref->getTarget()) );
-       switch (ref->getKind()) {
+       switch ( (x86::ReferenceKinds)(ref->getKind()) ) {
                case x86::kNoFixUp:
                case x86::kFollowOn:
                        // do nothing
                        break;
                case x86::kPointer:
+               case x86::kPointerWeakImport:
+               case x86::kAbsolute32:
                        {
                                if ( isExternal ) {
                                        // external realocation ==> pointer contains addend
@@ -2480,6 +2756,7 @@ void Writer<x86>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, co
                                        (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
                        break;
                case x86::kPCRel32:
+               case x86::kPCRel32WeakImport:
                        int64_t displacement = 0;
                        if ( isExternal )
                                displacement = ref->getTargetOffset() - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
@@ -2495,6 +2772,160 @@ void Writer<x86>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, co
        }
 }
 
+template <>
+void Writer<x86_64>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
+{
+       const int64_t twoGigLimit                 = 0x7FFFFFFF;
+       uint64_t* fixUp = (uint64_t*)&buffer[ref->getFixUpOffset()];
+       int64_t displacement = 0;
+       switch ( (x86_64::ReferenceKinds)(ref->getKind()) ) {
+               case x86_64::kNoFixUp:
+               case x86_64::kFollowOn:
+                       // do nothing
+                       break;
+               case x86_64::kPointerWeakImport:
+               case x86_64::kPointer:
+                       {
+                               //fprintf(stderr, "fixUpReferenceFinal: %s reference to %s\n", this->getDisplayName(), target.getDisplayName());
+                               if ( this->relocationNeededInFinalLinkedImage(ref->getTarget()) == kRelocExternal ) {
+                                       // external realocation ==> pointer contains addend
+                                       LittleEndian::set64(*fixUp, ref->getTargetOffset());
+                               }
+                               else {
+                                       // internal relocation
+                                       // pointer contains target address
+                                       //printf("Atom::fixUpReferenceFinal) target.name=%s, target.address=0x%08llX\n", target.getDisplayName(), target.getAddress());
+                                       LittleEndian::set64(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
+                               }
+                       }
+                       break;
+               case x86_64::kPointerDiff32:
+                               displacement = (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset());
+                               if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) )
+                                       throw "32-bit pointer difference out of range";
+                               LittleEndian::set32(*((uint32_t*)fixUp), (uint32_t)displacement);
+                               break;
+               case x86_64::kPointerDiff:
+                               LittleEndian::set64(*fixUp,
+                                       (ref->getTarget().getAddress() + ref->getTargetOffset()) - (ref->getFromTarget().getAddress() + ref->getFromTargetOffset()) );
+                               break;
+               case x86_64::kBranchPCRel32WeakImport:
+               case x86_64::kBranchPCRel32:
+               case x86_64::kPCRel32:
+               case x86_64::kPCRel32_1:
+               case x86_64::kPCRel32_2:
+               case x86_64::kPCRel32_4:
+               case x86_64::kPCRel32GOT:
+               case x86_64::kPCRel32GOTWeakImport:
+               case x86_64::kPCRel32GOTLoad:
+               case x86_64::kPCRel32GOTLoadWeakImport:
+                       switch ( ref->getTarget().getDefinitionKind() ) {
+                               case ObjectFile::Atom::kRegularDefinition:
+                               case ObjectFile::Atom::kWeakDefinition:
+                               case ObjectFile::Atom::kTentativeDefinition:
+                                       displacement = (ref->getTarget().getAddress() + (int32_t)ref->getTargetOffset()) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
+                                       break;
+                               case ObjectFile::Atom::kExternalDefinition:
+                               case ObjectFile::Atom::kExternalWeakDefinition:
+                                       throw "codegen problem, can't use rel32 to external symbol";
+                                       break;
+                       }
+                       switch ( ref->getKind() ) {
+                               case x86_64::kPCRel32_1:
+                                       displacement -= 1;
+                                       break;
+                               case x86_64::kPCRel32_2:
+                                       displacement -= 2;
+                                       break;
+                               case x86_64::kPCRel32_4:
+                                       displacement -= 4;
+                                       break;
+                       }
+                       if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) {
+                               //fprintf(stderr, "call out of range from %s in %s to %s in %s\n", this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath());
+                               throw "rel32 out of range";
+                       }
+                       LittleEndian::set32(*((uint32_t*)fixUp), (int32_t)displacement);
+                       break;
+       }
+}
+
+template <>
+void Writer<x86_64>::fixUpReferenceRelocatable(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
+{
+       const int64_t twoGigLimit                 = 0x7FFFFFFF;
+       bool external = (ref->getTarget().getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn);
+       uint64_t* fixUp = (uint64_t*)&buffer[ref->getFixUpOffset()];
+       int64_t displacement = 0;
+       int32_t temp32;
+       switch ( (x86_64::ReferenceKinds)(ref->getKind()) ) {
+               case x86_64::kNoFixUp:
+               case x86_64::kFollowOn:
+                       // do nothing
+                       break;
+               case x86_64::kPointer:
+               case x86_64::kPointerWeakImport:
+                       {
+                               if ( external ) {
+                                       // external realocation ==> pointer contains addend
+                                       LittleEndian::set64(*fixUp, ref->getTargetOffset());
+                               }
+                               else {
+                                       // internal relocation ==> pointer contains target address
+                                       LittleEndian::set64(*fixUp, ref->getTarget().getAddress() + ref->getTargetOffset());
+                               }
+                       }
+                       break;
+               case x86_64::kPointerDiff32:
+                               // addend in content
+                               LittleEndian::set32(*((uint32_t*)fixUp), ref->getTargetOffset() - ref->getFromTargetOffset() );
+                       break;
+               case x86_64::kPointerDiff:
+                               // addend in content
+                               LittleEndian::set64(*fixUp, ref->getTargetOffset() - ref->getFromTargetOffset() );
+                       break;
+               case x86_64::kBranchPCRel32:
+               case x86_64::kBranchPCRel32WeakImport:
+               case x86_64::kPCRel32:
+               case x86_64::kPCRel32_1:
+               case x86_64::kPCRel32_2:
+               case x86_64::kPCRel32_4:
+                       // turn unsigned 64-bit target offset in signed 32-bit offset, since that is what source originally had
+                       temp32 = ref->getTargetOffset();
+                       if ( external ) {
+                               // extern relocation contains addend
+                               displacement = temp32;
+                       }
+                       else {
+                               // internal relocations contain delta to target address
+                               displacement = (ref->getTarget().getAddress() + temp32) - (inAtom->getAddress() + ref->getFixUpOffset() + 4);
+                       }
+                       switch ( ref->getKind() ) {
+                               case x86_64::kPCRel32_1:
+                                       displacement -= 1;
+                                       break;
+                               case x86_64::kPCRel32_2:
+                                       displacement -= 2;
+                                       break;
+                               case x86_64::kPCRel32_4:
+                                       displacement -= 4;
+                                       break;
+                       }
+                       if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) {
+                               //fprintf(stderr, "call out of range from %s in %s to %s in %s\n", this->getDisplayName(), this->getFile()->getPath(), target.getDisplayName(), target.getFile()->getPath());
+                               throw "rel32 out of range";
+                       }
+                       LittleEndian::set32(*((uint32_t*)fixUp), (int32_t)displacement);
+                       break;
+               case x86_64::kPCRel32GOT:
+               case x86_64::kPCRel32GOTLoad:
+               case x86_64::kPCRel32GOTWeakImport:
+               case x86_64::kPCRel32GOTLoadWeakImport:
+                       // contains addend (usually zero)
+                       LittleEndian::set32(*((uint32_t*)fixUp), (uint32_t)(ref->getTargetOffset()));
+                       break;
+       }
+}
 
 template <>
 void Writer<ppc>::fixUpReferenceFinal(const ObjectFile::Reference* ref, const ObjectFile::Atom* inAtom, uint8_t buffer[]) const
@@ -2560,6 +2991,13 @@ void Writer<A>::fixUpReference_powerpc(const ObjectFile::Reference* ref, const O
                                                throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
                                        P::setP(*fixUpPointer, fDyldHelper->getAddress());
                                }
+                               else if ( !finalLinkedImage && ((SectionInfo*)inAtom->getSection())->fAllNonLazyPointers ) {
+                                       // indirect symbol table has INDIRECT_SYMBOL_LOCAL, so we must put address in content
+                                       if  ( ref->getTarget().getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableNotIn )
+                                               P::setP(*fixUpPointer, targetAddr);
+                                       else
+                                               P::setP(*fixUpPointer, 0);
+                               }
                                else if ( relocateableExternal ) {
                                        // external realocation ==> pointer contains addend
                                        P::setP(*fixUpPointer, ref->getTargetOffset());
@@ -2724,6 +3162,11 @@ bool Writer<x86>::stubableReferenceKind(uint8_t kind)
        return (kind == x86::kPCRel32 || kind == x86::kPCRel32WeakImport);
 }
 
+template <>
+bool Writer<x86_64>::stubableReferenceKind(uint8_t kind)
+{
+       return (kind == x86_64::kBranchPCRel32 || kind == x86_64::kBranchPCRel32WeakImport);
+}
 
 template <>
 bool Writer<ppc>::weakImportReferenceKind(uint8_t kind)
@@ -2743,6 +3186,18 @@ bool Writer<x86>::weakImportReferenceKind(uint8_t kind)
        return (kind == x86::kPCRel32WeakImport || kind == x86::kPointerWeakImport);
 }
 
+template <>
+bool Writer<x86_64>::weakImportReferenceKind(uint8_t kind)
+{
+       switch ( kind ) {
+               case x86_64::kPointerWeakImport:
+               case x86_64::kBranchPCRel32WeakImport:
+               case x86_64::kPCRel32GOTWeakImport:
+               case x86_64::kPCRel32GOTLoadWeakImport:
+                       return true;
+       }
+       return false;
+}
 
 
 template <>
@@ -2763,6 +3218,52 @@ bool Writer<x86>::GOTReferenceKind(uint8_t kind)
        return false;
 }
 
+template <>
+bool Writer<x86_64>::GOTReferenceKind(uint8_t kind)
+{
+       switch ( kind ) {
+               case x86_64::kPCRel32GOT:
+               case x86_64::kPCRel32GOTWeakImport:
+               case x86_64::kPCRel32GOTLoad:
+               case x86_64::kPCRel32GOTLoadWeakImport:
+                       return true;
+       }
+       return false;
+}
+
+template <typename A>
+void Writer<A>::scanForAbsoluteReferences()
+{
+       // do nothing
+}
+
+// for ppc64 look for any -mdynamic-no-pic codegen
+template <>
+void  Writer<ppc64>::scanForAbsoluteReferences()
+{
+       // only do this for main executable
+       if ( mightNeedPadSegment() && (fPageZeroAtom != NULL) ) {
+               for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms->begin(); it != fAllAtoms->end(); it++) {
+                       ObjectFile::Atom* atom = *it;
+                       std::vector<ObjectFile::Reference*>&  references = atom->getReferences();
+                       for (std::vector<ObjectFile::Reference*>::iterator rit=references.begin(); rit != references.end(); rit++) {
+                               ObjectFile::Reference* ref = *rit;
+                               switch (ref->getKind()) {
+                                       case ppc64::kAbsLow16:
+                                       case ppc64::kAbsLow14:
+                                       case ppc64::kAbsHigh16:
+                                       case ppc64::kAbsHigh16AddLow:
+                                               //fprintf(stderr, "found -mdyanmic-no-pic codegen in %s in %s\n", atom->getDisplayName(), atom->getFile()->getPath());
+                                               // shrink page-zero and add pad segment to compensate
+                                               fPadSegmentInfo = new SegmentInfo();
+                                               strcpy(fPadSegmentInfo->fName, "__4BGFILL");
+                                               fPageZeroAtom->setSize(0x1000);
+                                               return;
+                               }
+                       }
+               }
+       }
+}
 
 
 template <typename A>
@@ -2770,10 +3271,10 @@ 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::kDyld:
                case Options::kDynamicLibrary:
                case Options::kDynamicBundle:
                case Options::kDynamicExecutable:
@@ -2841,7 +3342,7 @@ void Writer<A>::synthesizeStubs()
                                        nlp = pos->second;
                                }
                                // alter reference to use non lazy pointer instead
-                               ref->setTarget(*nlp, 0);
+                               ref->setTarget(*nlp, ref->getTargetOffset());
                        }
                }
        }
@@ -2922,7 +3423,9 @@ void Writer<A>::synthesizeStubs()
                        ObjectFile::Atom* atom = *it;
                        ObjectFile::Section* nextSection = atom->getSection();
                        if ( nextSection != curSection ) {
-                               if ( (prevAtom != NULL) && (strcmp(prevAtom->getSectionName(), "__dyld") == 0) ) {
+                               if ( (prevAtom != NULL) 
+                                       && ((strcmp(prevAtom->getSectionName(), "__dyld") == 0) 
+                                       || ((fOptions.outputKind() == Options::kDyld) && (strcmp(prevAtom->getSectionName(), "__data") == 0))) ) {
                                        // found end of __dyld section, insert lazy pointers here
                                        fAllAtoms->insert(it, fAllSynthesizedNonLazyPointers.begin(), fAllSynthesizedNonLazyPointers.end());
                                        inserted = true;
@@ -2966,7 +3469,8 @@ void Writer<A>::partitionIntoSections()
                                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)) );
+                               currentSectionInfo->fVirtualSection = ( (currentSectionInfo->fSectionName[0] == '.') || 
+                                               (oneSegmentCommand && (atom->getDefinitionKind()==ObjectFile::Atom::kTentativeDefinition)) && !fOptions.makeTentativeDefinitionsReal() );
                                if ( !currentSectionInfo->fVirtualSection || fEmitVirtualSections )
                                        currentSectionInfo->setIndex(sectionIndex++);
                                currentSegmentInfo->fSections.push_back(currentSectionInfo);
@@ -3088,6 +3592,12 @@ bool Writer<x86>::addBranchIslands()
        return false;
 }
 
+template <>
+bool Writer<x86_64>::addBranchIslands()
+{
+       // x86 branches can reach entire 4G size of largest image
+       return false;
+}
 
 template <>
 inline uint8_t Writer<ppc>::branch24Reference()
@@ -3343,7 +3853,10 @@ void Writer<A>::assignFileOffsets()
                        
                        // adjust file offset to match address
                        if ( prevSection != NULL ) {
-                               fileOffset = (address - prevSection->getBaseAddress()) + prevSection->fFileOffset;
+                               if ( finalLinkedImage || !prevSection->fVirtualSection )
+                                       fileOffset = (address - prevSection->getBaseAddress()) + prevSection->fFileOffset;
+                               else
+                                       fileOffset = ( (fileOffset+alignment-1) & (-alignment) );
                        }
                        
                        // update section info
@@ -3357,7 +3870,8 @@ void Writer<A>::assignFileOffsets()
                                throwf("zero-fill section %s not at end of segment", curSection->fSectionName);
                        
                        // update running pointers
-                       address += curSection->fSize;
+                       if ( finalLinkedImage || !curSection->fVirtualSection )
+                               address += curSection->fSize;
                        fileOffset += curSection->fSize;
                        
                        // update segment info
@@ -3382,11 +3896,10 @@ void Writer<A>::assignFileOffsets()
                                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];
                        
@@ -3404,7 +3917,7 @@ void Writer<A>::assignFileOffsets()
                                                        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 {
+                                       else if ( (segment1->fSize != 0) && (segment2->fSize != 0) ) {
                                                        throwf("segments overlap: %s (0x%08llX + 0x%08llX) and %s (0x%08llX + 0x%08llX)",
                                                                segment1->fName, segment1->fBaseAddress, segment1->fSize, segment2->fName, segment2->fBaseAddress, segment2->fSize);
                                        }
@@ -3412,6 +3925,18 @@ void Writer<A>::assignFileOffsets()
                        }
                }
        }
+
+       // set up fFirstWritableSegment and fWritableSegmentPastFirst4GB
+       for (std::vector<SegmentInfo*>::iterator segit = fSegmentInfos.begin(); segit != fSegmentInfos.end(); ++segit) {
+               SegmentInfo* curSegment = *segit;
+               if ( (curSegment->fInitProtection & VM_PROT_WRITE) != 0 ) {
+                       if ( fFirstWritableSegment == NULL )
+                               fFirstWritableSegment = curSegment;
+                       if ( (curSegment->fBaseAddress + curSegment->fSize - fOptions.baseAddress()) >= 0x100000000LL )
+                               fWritableSegmentPastFirst4GB = true;
+               }
+       }
+       
 }
 
 template <typename A>
@@ -3426,6 +3951,21 @@ void Writer<A>::adjustLinkEditSections()
        const unsigned int sectionCount = lastSeg->fSections.size();
        uint64_t fileOffset = lastSeg->fSections[firstLinkEditSectionIndex]->fFileOffset;
        uint64_t address = lastSeg->fSections[firstLinkEditSectionIndex]->getBaseAddress();
+       if ( fPadSegmentInfo != NULL ) {
+               // insert __4GBFILL segment into segments vector before LINKEDIT
+               for(std::vector<SegmentInfo*>::iterator it = fSegmentInfos.begin(); it != fSegmentInfos.end(); ++it) {
+                       if ( *it == lastSeg ) {
+                               fSegmentInfos.insert(it, fPadSegmentInfo);
+                               break;
+                       }
+               }
+               // adjust  __4GBFILL segment to span from end of last segment to zeroPageSize
+               fPadSegmentInfo->fSize = fOptions.zeroPageSize() - address;
+               fPadSegmentInfo->fBaseAddress = address;
+               // adjust LINKEDIT to start at zeroPageSize
+               address = fOptions.zeroPageSize();
+               lastSeg->fBaseAddress = fOptions.zeroPageSize();
+       }
        for (unsigned int i=firstLinkEditSectionIndex; i < sectionCount; ++i) {
                std::vector<class ObjectFile::Atom*>& atoms = lastSeg->fSections[i]->fAtoms;
                const unsigned int atomCount = atoms.size();
@@ -3442,6 +3982,7 @@ void Writer<A>::adjustLinkEditSections()
                        if ( size > fLargestAtomSize )
                                fLargestAtomSize = size;
                }
+               //fprintf(stderr, "setting: lastSeg->fSections[%d]->fSize = 0x%08llX\n", i, sectionOffset);
                lastSeg->fSections[i]->fSize = sectionOffset;
                fileOffset += sectionOffset;
                address += sectionOffset;
@@ -3636,6 +4177,13 @@ void MachHeaderAtom<x86>::setHeaderInfo(macho_header<x86::P>& header) const
        header.set_cpusubtype(CPU_SUBTYPE_I386_ALL);
 }
 
+template <>
+void MachHeaderAtom<x86_64>::setHeaderInfo(macho_header<x86_64::P>& header) const
+{
+       header.set_magic(MH_MAGIC_64);
+       header.set_cputype(CPU_TYPE_X86_64);
+       header.set_cpusubtype(CPU_SUBTYPE_X86_64_ALL);
+}
 
 template <typename A>
 CustomStackAtom<A>::CustomStackAtom(Writer<A>& writer)
@@ -3666,6 +4214,11 @@ bool CustomStackAtom<x86>::stackGrowsDown()
        return true;
 }
 
+template <>
+bool CustomStackAtom<x86_64>::stackGrowsDown()
+{
+       return true;
+}
 
 template <typename A>
 void SegmentLoadCommandsAtom<A>::computeSize()
@@ -3684,6 +4237,10 @@ void SegmentLoadCommandsAtom<A>::computeSize()
        }
        fSize = size;
        fCommandCount = segCount;
+       if ( fWriter.fPadSegmentInfo != NULL ) {
+               ++fCommandCount;
+               fSize += sizeof(macho_segment_command<P>);
+       }
 }
 
 template <>
@@ -3704,6 +4261,11 @@ uint64_t LoadCommandAtom<x86>::alignedSize(uint64_t size)
        return ((size+3) & (-4));       // 4-byte align all load commands for 32-bit mach-o
 }
 
+template <>
+uint64_t LoadCommandAtom<x86_64>::alignedSize(uint64_t size)
+{
+       return ((size+7) & (-8));       // 8-byte align all load commands for 64-bit mach-o
+}
 
 
 template <typename A>
@@ -3766,7 +4328,7 @@ void SegmentLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
                                        sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
                                }
                                else if ( sectInfo->fAllStubs ) {
-                                       sect->set_flags(S_SYMBOL_STUBS);
+                                       sect->set_flags(S_SYMBOL_STUBS | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS);
                                        sect->set_reserved1(sectInfo->fIndirectSymbolOffset);
                                        sect->set_reserved2(sectInfo->fSize / sectInfo->fAtoms.size());
                                }
@@ -3802,9 +4364,15 @@ void SegmentLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
                                else if ( (strcmp(sectInfo->fSectionName, "__literal8") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
                                        sect->set_flags(S_8BYTE_LITERALS);
                                }
+                               else if ( (strcmp(sectInfo->fSectionName, "__literal16") == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
+                                       sect->set_flags(S_16BYTE_LITERALS);
+                               }
                                else if ( (strcmp(sectInfo->fSectionName, "__message_refs") == 0) && (strcmp(sectInfo->fSegmentName, "__OBJC") == 0) ) {
                                        sect->set_flags(S_LITERAL_POINTERS);
                                }
+                               else if ( (strncmp(sectInfo->fSectionName, "__text", 6) == 0) && (strcmp(sectInfo->fSegmentName, "__TEXT") == 0) ) {
+                                       sect->set_flags(S_REGULAR | S_ATTR_SOME_INSTRUCTIONS | S_ATTR_PURE_INSTRUCTIONS);
+                               }
                        }
                }
                p = &p[sizeof(macho_segment_command<P>) + sectionsEmitted*sizeof(macho_section<P>)];
@@ -4070,6 +4638,11 @@ uint64_t ThreadsLoadCommandsAtom<x86>::getSize() const
        return this->alignedSize(16 + 16*4);    // base size + i386_THREAD_STATE_COUNT * 4
 }
 
+template <>
+uint64_t ThreadsLoadCommandsAtom<x86_64>::getSize() const
+{
+       return this->alignedSize(16 + x86_THREAD_STATE64_COUNT * 4); 
+}
 
 template <>
 void ThreadsLoadCommandsAtom<ppc>::copyRawContent(uint8_t buffer[]) const
@@ -4101,7 +4674,7 @@ void ThreadsLoadCommandsAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
        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
+               cmd->set_thread_register(3, fWriter.fOptions.customStackAddr());        // r1
 }
 
 template <>
@@ -4121,6 +4694,21 @@ void ThreadsLoadCommandsAtom<x86>::copyRawContent(uint8_t buffer[]) const
 }
 
 
+template <>
+void ThreadsLoadCommandsAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
+{
+       uint64_t size = this->getSize();
+       uint64_t start = fWriter.getAtomLoadAddress(fWriter.fEntryPoint);
+       bzero(buffer, size);
+       macho_thread_command<x86_64::P>* cmd = (macho_thread_command<x86_64::P>*)buffer;
+       cmd->set_cmd(LC_UNIXTHREAD);
+       cmd->set_cmdsize(size);
+       cmd->set_flavor(x86_THREAD_STATE64);                    
+       cmd->set_count(x86_THREAD_STATE64_COUNT);       
+       cmd->set_thread_register(16, start);            // rip 
+       if ( fWriter.fOptions.hasCustomStack() )
+               cmd->set_thread_register(7, fWriter.fOptions.customStackAddr());        // uesp
+}
 
 
 template <typename A>
@@ -4343,7 +4931,7 @@ bool StubAtom<ppc64>::pic() const
        // This usually only happens when a large zero-page is requested
        switch ( fWriter.fOptions.outputKind() ) {
                case Options::kDynamicExecutable:
-                       return (fWriter.fOptions.zeroPageSize() > 4096);
+                       return (fWriter.fPageZeroAtom->getSize() > 4096);
                case Options::kDynamicLibrary:
                case Options::kDynamicBundle:
                        return true;
@@ -4406,6 +4994,15 @@ StubAtom<x86>::StubAtom(Writer<x86>& writer, ObjectFile::Atom& target)
        writer.fAllSynthesizedStubs.push_back(this);
 }
 
+template <>
+StubAtom<x86_64>::StubAtom(Writer<x86_64>& writer, ObjectFile::Atom& target)
+ : WriterAtom<x86_64>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
+{
+       writer.fAllSynthesizedStubs.push_back(this);
+
+       LazyPointerAtom<x86_64>* lp = new LazyPointerAtom<x86_64>(writer, target);
+       fReferences.push_back(new WriterReference<x86_64>(2, x86_64::kPCRel32, lp));
+}
 
 template <typename A>
 const char* StubAtom<A>::stubName(const char* name)
@@ -4433,6 +5030,11 @@ uint64_t StubAtom<x86>::getSize() const
        return 5;
 }
 
+template <>
+uint64_t StubAtom<x86_64>::getSize() const
+{
+       return 6;
+}
 
 template <>
 uint8_t StubAtom<x86>::getAlignment() const
@@ -4493,6 +5095,23 @@ void StubAtom<x86>::copyRawContent(uint8_t buffer[]) const
        buffer[4] = 0xF4;
 }
 
+template <>
+void StubAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
+{
+       buffer[0] = 0xFF;               // jmp *foo$lazy_pointer(%rip)
+       buffer[1] = 0x25;
+       buffer[2] = 0x00;
+       buffer[3] = 0x00;
+       buffer[4] = 0x00;
+       buffer[5] = 0x00;
+}
+
+// x86_64 stubs are 7 bytes and need no alignment
+template <>
+uint8_t StubAtom<x86_64>::getAlignment() const
+{
+       return 0;
+}
 
 template <>
 const char*    StubAtom<ppc>::getSectionName() const
@@ -4514,6 +5133,60 @@ const char*      StubAtom<x86>::getSectionName() const
 
 
 
+template <>
+StubHelperAtom<x86_64>::StubHelperAtom(Writer<x86_64>& writer, ObjectFile::Atom& target, ObjectFile::Atom& lazyPointer)
+ : WriterAtom<x86_64>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
+{
+       writer.fAllSynthesizedStubHelpers.push_back(this);
+
+       fReferences.push_back(new WriterReference<x86_64>(3, x86_64::kPCRel32, &lazyPointer));
+       fReferences.push_back(new WriterReference<x86_64>(8, x86_64::kPCRel32, writer.fDyldHelper));
+       if ( writer.fDyldHelper == NULL )
+               throw "symbol dyld_stub_binding_helper not defined (usually in crt1.o/dylib1.o/bundle1.o)";
+}
+
+template <>
+uint64_t StubHelperAtom<x86_64>::getSize() const
+{
+       return 12;
+}
+
+template <>
+void StubHelperAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
+{
+       buffer[0]  = 0x4C;              // lea foo$lazy_ptr(%rip),%r11
+       buffer[1]  = 0x8D;
+       buffer[2]  = 0x1D;
+       buffer[3]  = 0x00;
+       buffer[4]  = 0x00;
+       buffer[5]  = 0x00;
+       buffer[6]  = 0x00;
+       buffer[7]  = 0xE9;              // jmp dyld_stub_binding_helper
+       buffer[8]  = 0x00;
+       buffer[9]  = 0x00;
+       buffer[10] = 0x00;
+       buffer[11] = 0x00;
+}
+
+template <typename A>
+const char* StubHelperAtom<A>::stubName(const char* name)
+{
+       char* buf;
+       asprintf(&buf, "%s$stubHelper", name);
+       return buf;
+}
+
+
+// specialize lazy pointer for x86_64 to initially pointer to stub helper
+template <>
+LazyPointerAtom<x86_64>::LazyPointerAtom(Writer<x86_64>& writer, ObjectFile::Atom& target)
+ : WriterAtom<x86_64>(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target)
+{
+       writer.fAllSynthesizedLazyPointers.push_back(this);
+
+       StubHelperAtom<x86_64>* helper = new StubHelperAtom<x86_64>(writer, target, *this);
+       fReferences.push_back(new WriterReference<x86_64>(0, x86_64::kPointer, helper));
+}
 
 
 template <typename A>
index 7c51e0ae0456c4e5ddc2da85c543ab8339c612ca..4150fdae309e09a964c43d54d94e2974f5c89ec0 100644 (file)
@@ -289,15 +289,16 @@ static ObjectFile::Reader* createReader(const char* path, const ObjectFile::Read
        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);
+       uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, 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;
+               for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
+                       fprintf(stderr, "archs[i].cputype = %X\n", archs[i].cputype);
+                       if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)sPreferredArch ) {
+                               p = p + OSSwapBigToHostInt32(archs[i].offset);
                                mh = (struct mach_header*)p;
                        }
                }
@@ -308,6 +309,8 @@ static ObjectFile::Reader* createReader(const char* path, const ObjectFile::Read
                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);
+       else if ( mach_o::relocatable::Reader<x86_64>::validFile(p) )
+               return mach_o::relocatable::Reader<x86_64>::make(p, path, 0, options);
        throwf("not a mach-o object file: %s", path);
 }
 
@@ -336,6 +339,8 @@ int main(int argc, const char* argv[])
                                                sPreferredArch = CPU_TYPE_POWERPC;
                                        else if ( strcmp(arch, "i386") == 0 )
                                                sPreferredArch = CPU_TYPE_I386;
+                                       else if ( strcmp(arch, "x86_64") == 0 )
+                                               sPreferredArch = CPU_TYPE_X86_64;
                                        else 
                                                throwf("unknown architecture %s", arch);
                                }
index 0be49104af67e3db486456fa3157e1e48123d87c..98e59f4862d569a5c7c53d752da999dd43fa41a0 100644 (file)
@@ -59,13 +59,16 @@ struct LineInfo
 class ReaderOptions
 {
 public:
-                                               ReaderOptions() : fFullyLoadArchives(false), fLoadObjcClassesInArchives(false), fFlatNamespace(false),
-                                                                                 fDebugInfoStripping(kDebugInfoFull), fTraceDylibs(false), fTraceIndirectDylibs(false), fTraceArchives(false), fTraceOutputFile(NULL) {}
+                                               ReaderOptions() : fFullyLoadArchives(false), fLoadObjcClassesInArchives(false), fFlatNamespace(false), 
+                                                                               fForFinalLinkedImage(false), fWhyLoad(false), fDebugInfoStripping(kDebugInfoFull),
+                                                                                fTraceDylibs(false), fTraceIndirectDylibs(false), fTraceArchives(false), fTraceOutputFile(NULL) {}
        enum DebugInfoStripping { kDebugInfoNone, kDebugInfoMinimal, kDebugInfoFull };
 
        bool                            fFullyLoadArchives;
        bool                            fLoadObjcClassesInArchives;
        bool                            fFlatNamespace;
+       bool                            fForFinalLinkedImage;
+       bool                            fWhyLoad;
        DebugInfoStripping      fDebugInfoStripping;
        bool                            fTraceDylibs;
        bool                            fTraceIndirectDylibs;
@@ -190,7 +193,7 @@ class Atom
 public:
        enum Scope { scopeTranslationUnit, scopeLinkageUnit, scopeGlobal };
        enum DefinitionKind { kRegularDefinition, kWeakDefinition, kTentativeDefinition, kExternalDefinition, kExternalWeakDefinition };
-       enum SymbolTableInclusion { kSymbolTableNotIn, kSymbolTableIn, kSymbolTableInAndNeverStrip };
+       enum SymbolTableInclusion { kSymbolTableNotIn, kSymbolTableIn, kSymbolTableInAndNeverStrip, kSymbolTableInAsAbsolute };
 
        virtual Reader*                                                 getFile() const = 0;
        virtual bool                                                    getTranslationUnitSource(const char** dir, const char** name) const = 0;
@@ -199,6 +202,7 @@ public:
        virtual Scope                                                   getScope() const = 0;
        virtual DefinitionKind                                  getDefinitionKind() const = 0;
        virtual SymbolTableInclusion                    getSymbolTableInclusion() const = 0;
+       virtual bool                                                    dontDeadStrip() const = 0;
        virtual bool                                                    isZeroFill() const = 0;
        virtual uint64_t                                                getSize() const = 0;
        virtual std::vector<ObjectFile::Reference*>&  getReferences() const = 0;
@@ -218,23 +222,20 @@ public:
                        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; }
                        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), fDontDeadStrip(false) {}
+                                                                                       Atom() : fSegmentOffset(0), fSectionOffset(0), fSortOrder(0), fSection(NULL) {}
                virtual                                                         ~Atom() {}
 
                uint64_t                                                        fSegmentOffset;
                uint64_t                                                        fSectionOffset;
                unsigned int                                            fSortOrder;
                class Section*                                          fSection;
-               bool                                                            fDontDeadStrip;
 };
 
 
index 664bc416bdb99025661ec5c5fbcde8cced7771c6..e52b0ccc7e4053da79062ed50bbe85827ff652b5 100644 (file)
@@ -48,21 +48,23 @@ Options::Options(int argc, const char* argv[])
        : 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),
+         fVersionMin(kMinUnset),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),
+         fUmbrellaName(NULL), fInitFunctionName(NULL), fDotOutputFile(NULL), fExecutablePath(NULL), fBundleLoader(NULL),
+         fZeroPageSize(ULLONG_MAX), 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)
+         fTraceDylibSearching(false), fPause(false), fStatistics(false), fPrintOptions(false),
+         fMakeTentativeDefinitionsReal(false)
 {
        this->parsePreCommandLineEnvironmentSettings();
        this->parse(argc, argv);
        this->parsePostCommandLineEnvironmentSettings();
+       this->reconfigureDefaults();
        this->checkIllegalOptionCombinations();
 }
 
@@ -253,6 +255,11 @@ std::vector<const char*>& Options::initialUndefines()
        return fInitialUndefines;
 }
 
+bool Options::printWhyLive(const char* symbolName)
+{
+       return ( fWhyLive.find(symbolName) != fWhyLive.end() );
+}
+
 std::vector<const char*>& Options::traceSymbols()
 {
        return fTraceSymbols;
@@ -273,6 +280,26 @@ bool Options::hasExportRestrictList()
        return (fExportMode != kExportDefault);
 }
 
+bool Options::allGlobalsAreDeadStripRoots()
+{
+       // -exported_symbols_list means globals are not exported by default
+       if ( fExportMode == kExportSome ) 
+               return false;
+       //
+       switch ( fOutputKind ) {
+               case Options::kDynamicExecutable:
+               case Options::kStaticExecutable:
+                       // by default unused globals in a main executable are stripped
+                       return false;
+               case Options::kDynamicLibrary:
+               case Options::kDynamicBundle:
+               case Options::kObjectFile:
+               case Options::kDyld:
+                       return true;
+       }
+       return false;
+}
+
 uint32_t Options::minimumHeaderPad()
 {
        return fMinimumHeaderPad;
@@ -346,6 +373,8 @@ void Options::parseArch(const char* architecture)
                fArchitecture = CPU_TYPE_POWERPC64;
        else if ( strcmp(architecture, "i386") == 0 )
                fArchitecture = CPU_TYPE_I386;
+       else if ( strcmp(architecture, "x86_64") == 0 )
+               fArchitecture = CPU_TYPE_X86_64;
        else
                throw "-arch followed by unknown architecture name";
 }
@@ -512,18 +541,41 @@ Options::FileInfo Options::findFile(const char* path)
 
 void Options::loadFileList(const char* fileOfPaths)
 {
-       FILE* file = fopen(fileOfPaths, "r");
-       if ( file == NULL )
-               throwf("-filelist file not found: %s\n", fileOfPaths);
+       FILE* file;
+       const char* comma = strrchr(fileOfPaths, ',');
+       const char* prefix = NULL;
+       if ( comma != NULL ) {
+               prefix = comma+1;
+               int realFileOfPathsLen = comma-fileOfPaths;
+               char realFileOfPaths[realFileOfPathsLen+1];
+               strncpy(realFileOfPaths,fileOfPaths, realFileOfPathsLen);
+               realFileOfPaths[realFileOfPathsLen] = '\0';
+               file = fopen(realFileOfPaths, "r");
+               if ( file == NULL )
+                       throwf("-filelist file not found: %s\n", realFileOfPaths);
+       }
+       else {
+               file = fopen(fileOfPaths, "r");
+               if ( file == NULL )
+                       throwf("-filelist file not found: %s\n", fileOfPaths);
+       }
 
-       char path[1024];
+       char path[PATH_MAX];
        while ( fgets(path, 1024, file) != NULL ) {
-               path[1023] = '\0';
+               path[PATH_MAX-1] = '\0';
                char* eol = strchr(path, '\n');
                if ( eol != NULL )
                        *eol = '\0';
-
-               fInputFiles.push_back(findFile(path));
+               if ( prefix != NULL ) {
+                       char builtPath[strlen(prefix)+strlen(path)+2];
+                       strcpy(builtPath, prefix);
+                       strcat(builtPath, "/");
+                       strcat(builtPath, path);
+                       fInputFiles.push_back(findFile(builtPath));
+               }
+               else {
+                       fInputFiles.push_back(findFile(path));
+               }
        }
        fclose(file);
 }
@@ -636,18 +688,30 @@ 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
-               fprintf(stderr, "ld64: unknown option to -macosx_version_min");
+       if ( (strncmp(version, "10.", 3) == 0) && isdigit(version[3]) ) {
+               int num = version[3] - '0';
+               switch ( num ) {
+                       case 0:
+                       case 1:
+                               fVersionMin = k10_1;
+                               break;
+                       case 2:
+                               fVersionMin = k10_2;
+                               break;
+                       case 3:
+                               fVersionMin = k10_3;
+                               break;
+                       case 4:
+                               fVersionMin = k10_4;
+                               break;
+                       default:
+                               fVersionMin = k10_5;
+                               break;
+                       }
+       }
+       else {
+               fprintf(stderr, "ld64: unknown option to -macosx_version_min not 10.x");
+       }
 }
 
 void Options::setWeakReferenceMismatchTreatment(const char* treatment)
@@ -898,7 +962,7 @@ void Options::parse(int argc, const char* argv[])
                                fDylibInstallName = argv[++i];
                        }
                        // Sets the base address of the output.
-                       else if ( strcmp(arg, "-seg1addr") == 0 ) {
+                       else if ( (strcmp(arg, "-seg1addr") == 0) || (strcmp(arg, "-image_base") == 0) ) {
                                fBaseAddress = parseAddress(argv[++i]);
                        }
                        else if ( strcmp(arg, "-e") == 0 ) {
@@ -1074,7 +1138,10 @@ void Options::parse(int argc, const char* argv[])
                        }
                        else if ( strcmp(arg, "-pagezero_size") == 0 ) {
                                fZeroPageSize = parseAddress(argv[++i]);
-                               fZeroPageSize &= (-4096); // page align
+                               uint64_t temp = fZeroPageSize & (-4096); // page align
+                               if ( fZeroPageSize != temp )
+                                       fprintf(stderr, "ld64: warning, -pagezero_size not page aligned, rounding down\n");
+                                fZeroPageSize = temp;
                        }
                        else if ( strcmp(arg, "-stack_addr") == 0 ) {
                                fStackAddr = parseAddress(argv[++i]);
@@ -1097,8 +1164,12 @@ void Options::parse(int argc, const char* argv[])
                                i += 2;
                        }
                        else if ( strcmp(arg, "-bundle_loader") == 0 ) {
-                               // FIX FIX
-                               ++i;
+                               fBundleLoader = argv[++i];
+                               if ( (fBundleLoader == NULL) || (fBundleLoader[0] == '-') )
+                                       throw "-bundle_loader missing <path>";
+                               FileInfo info = findFile(fBundleLoader);
+                               info.options.fBundleLoader = true;
+                               fInputFiles.push_back(info);
                        }
                        else if ( strcmp(arg, "-private_bundle") == 0 ) {
                                // FIX FIX
@@ -1154,8 +1225,14 @@ void Options::parse(int argc, const char* argv[])
                        else if ( strcmp(arg, "-m") == 0 ) {
                                fWarnOnMultiplyDefined = true;
                        }
-                       else if ( strcmp(arg, "-whyload") == 0 ) {
-                                // FIX FIX
+                       else if ( (strcmp(arg, "-why_load") == 0) || (strcmp(arg, "-whyload") == 0) ) {
+                                fReaderOptions.fWhyLoad = true;
+                       }
+                       else if ( strcmp(arg, "-why_live") == 0 ) {
+                                const char* name = argv[++i];
+                               if ( name == NULL )
+                                       throw "-why_live missing symbol name argument";
+                               fWhyLive.insert(name);
                        }
                        else if ( strcmp(arg, "-u") == 0 ) {
                                const char* name = argv[++i];
@@ -1193,12 +1270,10 @@ void Options::parse(int argc, const char* argv[])
                                fReaderOptions.fDebugInfoStripping = ObjectFile::ReaderOptions::kDebugInfoMinimal;
                        }
                        else if ( strcmp(arg, "-dead_strip") == 0 ) {
-                               //fDeadStrip = kDeadStripOnPlusUnusedInits;
-                                fprintf(stderr, "ld64: warning -dead_strip not yet supported in ld64\n");
+                               fDeadStrip = kDeadStripOnPlusUnusedInits;
                        }
                        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");
+                               fDeadStrip = kDeadStripOn;
                        }
                        else if ( strcmp(arg, "-w") == 0 ) {
                                // FIX FIX
@@ -1292,6 +1367,9 @@ void Options::parse(int argc, const char* argv[])
                        else if ( strcmp(arg, "-print_statistics") == 0 ) {
                                fStatistics = true;
                        }
+                       else if ( strcmp(arg, "-d") == 0 ) {
+                               fMakeTentativeDefinitionsReal = true;
+                       }
                        else if ( strcmp(arg, "-v") == 0 ) {
                                // previously handled by buildSearchPaths()
                        }
@@ -1319,6 +1397,8 @@ void Options::parse(int argc, const char* argv[])
        }
 }
 
+
+
 //
 // -syslibroot <path> is used for SDK support.
 // The rule is that all search paths (both explicit and default) are
@@ -1476,6 +1556,64 @@ void Options::parsePostCommandLineEnvironmentSettings()
        if ( fExecutablePath == NULL && (fOutputKind == kDynamicExecutable) ) {
                fExecutablePath = fOutputFile;
        }
+       
+}
+
+void Options::reconfigureDefaults()
+{
+       // sync reader options
+       switch ( fOutputKind ) {
+               case Options::kObjectFile:
+                       fReaderOptions.fForFinalLinkedImage = false;
+                       break;
+               case Options::kDynamicExecutable:
+               case Options::kStaticExecutable:
+               case Options::kDynamicLibrary:
+               case Options::kDynamicBundle:
+               case Options::kDyld:
+                       fReaderOptions.fForFinalLinkedImage = true;
+                       break;
+       }
+
+       // set default min OS version
+       if ( fVersionMin == kMinUnset ) {
+               switch ( fArchitecture ) {
+                       case CPU_TYPE_POWERPC:
+                               fVersionMin = k10_2;
+                               break;
+                       case CPU_TYPE_I386:
+                       case CPU_TYPE_POWERPC64:
+                       case CPU_TYPE_X86_64:
+                               fVersionMin = k10_4;
+                       default:
+                               // architecture not specified
+                               fVersionMin = k10_4;
+                               break;
+               }
+       }
+
+       // adjust min based on architecture
+       switch ( fArchitecture ) {
+               case CPU_TYPE_I386:
+                       if ( fVersionMin < k10_4 ) {
+                               //fprintf(stderr, "ld64 warning: -macosx_version_min should be 10.4 or later for i386\n");
+                               fVersionMin = k10_4;
+                       }
+                       break;
+               case CPU_TYPE_POWERPC64:
+                       if ( fVersionMin < k10_4 ) {
+                               //fprintf(stderr, "ld64 warning: -macosx_version_min should be 10.4 or later for ppc64\n");
+                               fVersionMin = k10_4;
+                       }
+                       break;
+               case CPU_TYPE_X86_64:
+                       if ( fVersionMin < k10_4 ) {
+                               //fprintf(stderr, "ld64 warning: -macosx_version_min should be 10.4 or later for x86_64\n");
+                               fVersionMin = k10_4;
+                       }
+                       break;
+       }
+       
 }
 
 void Options::checkIllegalOptionCombinations()
@@ -1522,7 +1660,7 @@ void Options::checkIllegalOptionCombinations()
                        const char* lastSlash = strrchr(info.path, '/');
                        if ( lastSlash == NULL )
                                lastSlash = info.path - 1;
-                       const char* dot = strchr(lastSlash, '.');
+                       const char* dot = strchr(&lastSlash[1], '.');
                        if ( dot == NULL )
                                dot = &lastSlash[strlen(lastSlash)];
                        if ( strncmp(&lastSlash[1], subLibrary, dot-lastSlash-1) == 0 ) {
@@ -1548,6 +1686,7 @@ void Options::checkIllegalOptionCombinations()
                                        throw "-stack_addr must be < 4G for 32-bit processes";
                                break;
                        case CPU_TYPE_POWERPC64:
+                       case CPU_TYPE_X86_64:
                                break;
                }
                if ( (fStackAddr & -4096) != fStackAddr )
@@ -1564,14 +1703,15 @@ void Options::checkIllegalOptionCombinations()
                                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;
                                }
+                               if ( (fStackAddr > 0xB0000000) && ((fStackAddr-fStackSize) < 0xB0000000) )
+                                       fprintf(stderr, "ld64 warning: custom stack placement overlaps and will disable shared region\n");
                                break;
                        case CPU_TYPE_POWERPC64:
+                       case CPU_TYPE_X86_64:
                                if ( fStackAddr == 0 ) {
-                                       fprintf(stderr, "ld64 warning: -stack_addr not specified, using the default 0x0008000000000000\n");
-                                       fStackAddr = 0x0008000000000000LL;
+                                       fStackAddr = 0x0007FFFF00000000LL;
                                }
                                break;
                }
@@ -1613,6 +1753,14 @@ void Options::checkIllegalOptionCombinations()
        if ( (fInitFunctionName != NULL) && (fOutputKind != Options::kDynamicLibrary) )
                throw "-init can only be used with -dynamiclib";
 
+       // check -bundle_loader only used with -bundle
+       if ( (fBundleLoader != NULL) && (fOutputKind != Options::kDynamicBundle) )
+               throw "-bundle_loader can only be used with -bundle";
+
+       // check -d can only be used with -r
+       if ( fMakeTentativeDefinitionsReal && (fOutputKind != Options::kObjectFile) )
+               throw "-d can only be used with -r";
+       
        // make sure all required exported symbols exist
        for (NameSet::iterator it=fExportSymbols.begin(); it != fExportSymbols.end(); it++) {
                const char* name = *it;
@@ -1620,5 +1768,51 @@ void Options::checkIllegalOptionCombinations()
                if ( strcmp(&name[strlen(name)-3], ".eh") != 0 )
                        fInitialUndefines.push_back(name);
        }
+       
+       // make sure that -init symbol exist
+       if ( fInitFunctionName != NULL )
+               fInitialUndefines.push_back(fInitFunctionName);
+
+       if ( fZeroPageSize == ULLONG_MAX ) {
+               // zero page size not specified on command line, set default
+               switch (fArchitecture) {
+                       case CPU_TYPE_I386:
+                       case CPU_TYPE_POWERPC:
+                               // first 4KB for 32-bit architectures
+                               fZeroPageSize = 0x1000;
+                               break;
+                       case CPU_TYPE_POWERPC64:
+                               // first 4GB for ppc64 on 10.5
+                               if ( fVersionMin >= k10_5 )
+                                       fZeroPageSize = 0x100000000ULL;
+                               else
+                                       fZeroPageSize = 0x1000; // 10.4 dyld may not be able to handle >4GB zero page
+                               break;
+                       case CPU_TYPE_X86_64:
+                               // first 4GB for x86_64 on all OS's
+                               fZeroPageSize = 0x100000000ULL;
+                               break;
+                       default:
+                               // if -arch not used, default to 4K zero-page
+                               fZeroPageSize = 0x1000;
+               }
+       }
+       else {
+               switch ( fOutputKind ) {
+                       case Options::kDynamicExecutable:
+                       case Options::kStaticExecutable:
+                               // -pagezero_size size only legal when building main executable
+                               break;
+                       case Options::kDynamicLibrary:
+                       case Options::kDynamicBundle:
+                       case Options::kObjectFile:
+                       case Options::kDyld:
+                               throw "-pagezero_size option can only be used when linking a main executable";
+               }       
+       }
+
+       // -dead_strip and -r are incompatible
+       if ( (fDeadStrip != kDeadStripOff) && (fOutputKind == Options::kObjectFile) )
+               throw "-r and -dead_strip cannot be used together\n";
 
 }
index c8ef861235e9cbb4c8f833523eb7956594fe28fc..dcedf8e76942b5942e069aa0654f2c0dc1b36147 100644 (file)
@@ -39,10 +39,11 @@ void throwf (const char* format, ...) __attribute__ ((noreturn));
 class DynamicLibraryOptions
 {
 public:
-       DynamicLibraryOptions() : fWeakImport(false), fReExport(false), fInstallPathOverride(NULL) {}
+       DynamicLibraryOptions() : fWeakImport(false), fReExport(false), fBundleLoader(false), fInstallPathOverride(NULL) {}
 
        bool            fWeakImport;
        bool            fReExport;
+       bool            fBundleLoader;
        const char* fInstallPathOverride;
 };
 
@@ -70,7 +71,7 @@ public:
                                                                                  kWeakReferenceMismatchNonWeak };
        enum CommonsMode { kCommonsIgnoreDylibs, kCommonsOverriddenByDylibs, kCommonsConflictsDylibsError };
        enum DeadStripMode { kDeadStripOff, kDeadStripOn, kDeadStripOnPlusUnusedInits };
-       enum VersionMin { k10_1, k10_2, k10_3, k10_4, k10_5 };
+       enum VersionMin { kMinUnset, k10_1, k10_2, k10_3, k10_4, k10_5 };
 
        struct FileInfo {
                const char*                             path;
@@ -113,6 +114,7 @@ public:
        bool                                            keepPrivateExterns();   // only for kObjectFile
        bool                                            interposable();                 // only for kDynamicLibrary
        bool                                            hasExportRestrictList();
+       bool                                            allGlobalsAreDeadStripRoots();
        bool                                            shouldExport(const char*);
        bool                                            ignoreOtherArchInputFiles();
        bool                                            forceCpuSubtypeAll();
@@ -138,6 +140,7 @@ public:
        uint64_t                                        customStackAddr();
        bool                                            hasExecutableStack();
        std::vector<const char*>&       initialUndefines();
+       bool                                            printWhyLive(const char* name);
        uint32_t                                        minimumHeaderPad();
        std::vector<ExtraSection>&      extraSections();
        std::vector<SectionAlignment>&  sectionAlignments();
@@ -150,6 +153,8 @@ public:
        bool                                            warnStabs();
        bool                                            pauseAtEnd() { return fPause; }
        bool                                            printStatistics() { return fStatistics; }
+       bool                                            printArchPrefix() { return fMessagesPrefixedWithArchitecture; }
+       bool                                            makeTentativeDefinitionsReal() { return fMakeTentativeDefinitionsReal; }
 
 private:
        class CStringEquals
@@ -186,6 +191,7 @@ private:
        void                                            addSectionAlignment(const char* segment, const char* section, const char* alignment);
        CommonsMode                                     parseCommonsTreatment(const char* mode);
        Treatment                                       parseTreatment(const char* treatment);
+       void                                            reconfigureDefaults();
 
 
 
@@ -228,6 +234,7 @@ private:
        const char*                                                     fInitFunctionName;
        const char*                                                     fDotOutputFile;
        const char*                                                     fExecutablePath;
+       const char*                                                     fBundleLoader;
        uint64_t                                                        fZeroPageSize;
        uint64_t                                                        fStackSize;
        uint64_t                                                        fStackAddr;
@@ -243,7 +250,9 @@ private:
        bool                                                            fPause;
        bool                                                            fStatistics;
        bool                                                            fPrintOptions;
+       bool                                                            fMakeTentativeDefinitionsReal;
        std::vector<const char*>                        fInitialUndefines;
+       NameSet                                                         fWhyLive;
        std::vector<const char*>                        fTraceSymbols;
        unsigned long                                           fLimitUndefinedSymbols;
        std::vector<ExtraSection>                       fExtraSections;
index 7296c1a96e16df0d9a0361d9a0cc5cbeaa715ac6..a77a78746b179be87e60808f9b3740b2a2d4bcf6 100644 (file)
@@ -70,6 +70,7 @@ public:
        virtual Scope                                                           getScope() const                        { return ObjectFile::Atom::scopeTranslationUnit; }
        virtual DefinitionKind                                          getDefinitionKind() const       { return kRegularDefinition; }
        virtual SymbolTableInclusion                            getSymbolTableInclusion() const { return ObjectFile::Atom::kSymbolTableNotIn; }
+       virtual bool                                                            dontDeadStrip() const           { return true; }
        virtual bool                                                            isZeroFill() const                      { return false; }
        virtual uint64_t                                                        getSize() const                         { return fFileLength; }
        virtual std::vector<ObjectFile::Reference*>&  getReferences() const             { return fgEmptyReferenceList; }
@@ -88,7 +89,7 @@ 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) { setDontDeadStrip(); }
+                                                                                               : fOwner(owner), fSegment(segment), fSectionName(sectionName), fFileContent(fileContent), fFileLength(fileLength) { }
        virtual                                                                 ~Atom() {}
        
        Reader&                                                                 fOwner;
index e98df10b0c335dd3f1cad8fcbafbb85d8bb543be..e26c58162a260caa0d48706955287ae37536ec90 100644 (file)
@@ -28,6 +28,7 @@
 #include <sys/sysctl.h>
 #include <fcntl.h>
 #include <errno.h>
+#include <limits.h>
 #include <unistd.h>
 #include <mach/mach_time.h>
 #include <mach/vm_statistics.h>
@@ -283,6 +284,10 @@ class Linker {
 public:
                                                Linker(int argc, const char* argv[]);
 
+       const char*                     getArchPrefix();
+       const char*                     architectureName();
+       bool                            showArchitectureInErrors();
+       bool                            isInferredArchitecture();
        void                            createReaders();
        void                            createWriter();
        void                            addInputFile(ObjectFile::Reader* reader);
@@ -291,14 +296,23 @@ public:
 
 
 private:
+       struct WhyLiveBackChain
+       {
+               WhyLiveBackChain*       previous;
+               const char*                     name;
+       };
+
        ObjectFile::Reader*     createReader(const Options::FileInfo&);
        void                            addAtom(ObjectFile::Atom& atom);
        void                            addAtoms(std::vector<class ObjectFile::Atom*>& atoms);
        void                            buildAtomList();
+       void                            loadAndResolve();
        void                            loadUndefines();
+       void                            checkUndefines();
        void                            addWeakAtomOverrides();
        void                            resolveReferences();
-       void                            deadStrip();
+       void                            deadStripResolve();
+       void                            addLiveRoot(const char* name);
        void                            sortAtoms();
        void                            tweakLayout();
        void                            writeDotOutput();
@@ -309,8 +323,8 @@ private:
        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                            markLive(ObjectFile::Atom& atom, Linker::WhyLiveBackChain* previous);
+       void                            collectStabs(ObjectFile::Reader* reader, std::map<class ObjectFile::Atom*, uint32_t>& atomOrdinals);
        void                            synthesizeStabs(ObjectFile::Reader* reader);
        void                            printStatistics();
        void                            printTime(const char* msg, uint64_t partTime, uint64_t totalTime);
@@ -330,6 +344,8 @@ private:
        bool                            haveDirectLibrary(const char* path);
 
        void                            logTraceInfo(const char* format, ...);
+
+
        class SymbolTable
        {
        public:
@@ -373,12 +389,16 @@ private:
        std::vector<class ObjectFile::Reader*>                          fReadersThatHaveSuppliedAtoms;
        std::vector<class ObjectFile::Atom*>                            fAllAtoms;
        std::set<class ObjectFile::Atom*>                                       fDeadAtoms;
+       std::set<ObjectFile::Atom*>                                                     fLiveAtoms;
+       std::set<ObjectFile::Atom*>                                                     fLiveRootAtoms;
        std::vector<class ObjectFile::Reader::Stab>                     fStabs;
        bool                                                                                            fCreateUUID;
        SectionOrder                                                                            fSectionOrder;
        unsigned int                                                                            fNextSortOrder;
        unsigned int                                                                            fNextObjectFileOrder;
        cpu_type_t                                                                                      fArchitecture;
+       const char*                                                                                     fArchitectureName;
+       bool                                                                                            fArchitectureInferred;
        bool                                                                                            fDirectLibrariesComplete;
        uint64_t                                                                                        fOutputFileSize;
        uint64_t                                                                                        fStartTime;
@@ -401,23 +421,57 @@ private:
 
 Linker::Linker(int argc, const char* argv[])
        : fOptions(argc, argv), fGlobalSymbolTable(*this), fOutputFile(NULL), fCreateUUID(false), fNextSortOrder(1),
-         fNextObjectFileOrder(1), fArchitecture(0), fDirectLibrariesComplete(false), fOutputFileSize(0), fTotalObjectSize(0),
+         fNextObjectFileOrder(1), fArchitecture(0), fArchitectureInferred(false), 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();
+               fArchitectureInferred = true;
+       }
+       switch (fArchitecture) {
+               case CPU_TYPE_POWERPC:
+                       fArchitectureName = "ppc";
+                       break;
+               case CPU_TYPE_POWERPC64:
+                       fArchitectureName = "ppc64";
+                       break;
+               case CPU_TYPE_I386:
+                       fArchitectureName = "i386";
+                       break;
+               case CPU_TYPE_X86_64:
+                       fArchitectureName = "x86_64";
+                       break;
+               default:
+                       fArchitectureName = "unknown architecture";
+                       break;
        }
 }
 
+const char*    Linker::architectureName()
+{
+       return fArchitectureName;
+}
+
+bool Linker::showArchitectureInErrors()
+{
+       return fOptions.printArchPrefix();
+}
+
+bool Linker::isInferredArchitecture()
+{
+       return fArchitectureInferred;
+}
+
 cpu_type_t Linker::inferArchitecture()
 {
-       // scan all input files, looking for a thin .o file.  
+       // 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();
@@ -428,21 +482,25 @@ cpu_type_t Linker::inferArchitecture()
                        ::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);
+                                       //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);
+                                       //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);
+                                       //fprintf(stderr, "ld64 warning: -arch not used, infering -arch i386 based on %s\n", it->path);
                                        return CPU_TYPE_I386;
                                }
+                               else if ( mach_o::relocatable::Reader<x86_64>::validFile(buffer) ) {
+                                       //fprintf(stderr, "ld64 warning: -arch not used, infering -arch x86_64 based on %s\n", it->path);
+                                       return CPU_TYPE_X86_64;
+                               }
                        }
                }
        }
-       
+
        // no thin .o files found, so default to same architecture this was built as
        fprintf(stderr, "ld64 warning: -arch not specified\n");
 #if __ppc__
@@ -451,6 +509,8 @@ cpu_type_t Linker::inferArchitecture()
        return CPU_TYPE_I386;
 #elif __ppc64__
        return CPU_TYPE_POWERPC64;
+#elif __x86_64__
+       return CPU_TYPE_X86_64;
 #else
        #error unknown default architecture
 #endif
@@ -468,12 +528,45 @@ void Linker::setOutputFile(ExecutableFile::Writer* writer)
        fOutputFile = writer;
 }
 
+class InSet
+{
+public:
+       InSet(std::set<ObjectFile::Atom*>& deadAtoms) : fDeadAtoms(deadAtoms) {}
+
+       bool operator()(ObjectFile::Atom*& atom) const {
+               return ( fDeadAtoms.count(atom) != 0 );
+       }
+
+private:
+       std::set<ObjectFile::Atom*>& fDeadAtoms;
+};
+
+void Linker::loadAndResolve()
+{
+       if ( fOptions.deadStrip() == Options::kDeadStripOff ) {
+               // without dead-code-stripping:
+               // find atoms to resolve all undefines
+               this->loadUndefines();
+               // verify nothing is missing
+               this->checkUndefines();
+               // once all undefines fulfill, then bind all references
+               this->resolveReferences();
+               // remove atoms weak atoms that have been overridden
+               fAllAtoms.erase(std::remove_if(fAllAtoms.begin(), fAllAtoms.end(), InSet(fDeadAtoms)), fAllAtoms.end());
+       }
+       else {
+               // with dead code stripping:
+               // start binding references from roots,
+               this->deadStripResolve();
+               // verify nothing is missing
+               this->checkUndefines();
+       }
+}
+
 void Linker::link()
 {
        this->buildAtomList();
-       this->loadUndefines();
-       this->resolveReferences();
-       this->deadStrip();
+       this->loadAndResolve();
        this->sortAtoms();
        this->tweakLayout();
        this->writeDotOutput();
@@ -569,15 +662,21 @@ 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++) {
-               ObjectFile::Reference* reference = *it;
-               if ( reference->isTargetUnbound() ) {
-                       fGlobalSymbolTable.require(reference->getTargetName());
+       if ( fOptions.deadStrip() == Options::kDeadStripOff ) {
+               // not dead-stripping code, so add atom's references's names to symbol table as to-be-resolved-later
+               std::vector<class ObjectFile::Reference*>& references = atom.getReferences();
+               for (std::vector<ObjectFile::Reference*>::iterator it=references.begin(); it != references.end(); it++) {
+                       ObjectFile::Reference* reference = *it;
+                       if ( reference->isTargetUnbound() ) {
+                               fGlobalSymbolTable.require(reference->getTargetName());
+                       }
+                       if ( reference->hasFromTarget() && reference->isFromTargetUnbound() )
+                               fGlobalSymbolTable.require(reference->getFromTargetName());
                }
-               if ( reference->hasFromTarget() && reference->isFromTargetUnbound() )
-                       fGlobalSymbolTable.require(reference->getFromTargetName());
+       }
+       else {
+               if ( atom.dontDeadStrip() )
+                       fLiveRootAtoms.insert(&atom);
        }
 
        // if in global namespace, add atom itself to symbol table
@@ -671,7 +770,10 @@ void Linker::loadUndefines()
                                this->addJustInTimeAtoms(name);
                }
        }
+}
 
+void Linker::checkUndefines()
+{
        if ( fOptions.outputKind() != Options::kObjectFile ) {
                // error out on any remaining undefines
                bool doPrint = true;
@@ -696,7 +798,10 @@ void Linker::loadUndefines()
                int unresolvableExportsCount  = 0;
                if ( unresolvableCount != 0 ) {
                        if ( doPrint ) {
-                               fprintf(stderr, "can't resolve symbols:\n");
+                               if ( fOptions.printArchPrefix() )
+                                       fprintf(stderr, "Undefined symbols for architecture %s:\n", fArchitectureName);
+                               else
+                                       fprintf(stderr, "Undefined symbols:\n");
                                for (int i=0; i < unresolvableCount; ++i) {
                                        const char* name = unresolvableUndefines[i];
                                        fprintf(stderr, "  %s, referenced from:\n", name);
@@ -731,12 +836,6 @@ 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 )
-                               throwf("symbol %s not found for -init", fOptions.initFunctionName());
-               }
        }
 }
 
@@ -802,7 +901,7 @@ void Linker::resolve(ObjectFile::Reference* reference)
        const char* targetName = reference->getTargetName();
        ObjectFile::Atom* target = fGlobalSymbolTable.find(targetName);
        if ( target == NULL ) {
-               fprintf(stderr, "can't resolve: %s\n", targetName);
+               fprintf(stderr, "Undefined symbol: %s\n", targetName);
        }
        reference->setTarget(*target, reference->getTargetOffset());
 }
@@ -813,7 +912,7 @@ void Linker::resolveFrom(ObjectFile::Reference* reference)
        const char* fromTargetName = reference->getFromTargetName();
        ObjectFile::Atom* fromTarget = fGlobalSymbolTable.find(fromTargetName);
        if ( fromTarget == NULL ) {
-               fprintf(stderr, "can't resolve: %s\n", fromTargetName);
+               fprintf(stderr, "Undefined symbol: %s\n", fromTargetName);
        }
        reference->setFromTarget(*fromTarget);
 }
@@ -836,18 +935,6 @@ void Linker::resolveReferences()
        }
 }
 
-class InSet
-{
-public:
-       InSet(std::set<ObjectFile::Atom*>& deadAtoms) : fDeadAtoms(deadAtoms) {}
-
-       bool operator()(ObjectFile::Atom*& atom) const {
-               return ( fDeadAtoms.count(atom) != 0 );
-       }
-
-private:
-       std::set<ObjectFile::Atom*>& fDeadAtoms;
-};
 
 // used to remove stabs associated with atoms that won't be in output file
 class NotInSet
@@ -867,81 +954,144 @@ private:
 };
 
 
-class DeadStrippable
+class NotLive
 {
 public:
-       DeadStrippable()  {}
+       NotLive(std::set<ObjectFile::Atom*>& set) : fLiveAtoms(set)  {}
 
        bool operator()(ObjectFile::Atom*& atom) const {
-               //if ( ! atom->dontDeadStrip() )
+               //if ( fLiveAtoms.count(atom) == 0 )
                //      fprintf(stderr, "dead strip %s\n", atom->getDisplayName());
-               return ( ! atom->dontDeadStrip() );
+               return ( fLiveAtoms.count(atom) == 0 );
        }
+private:
+       std::set<ObjectFile::Atom*>& fLiveAtoms;
 };
 
-void Linker::markLive(ObjectFile::Atom* atom, std::set<ObjectFile::Atom*>& liveAtoms)
+
+
+void Linker::markLive(ObjectFile::Atom& atom, struct Linker::WhyLiveBackChain* previous)
 {
-       if ( liveAtoms.count(atom) == 0 ) {
+       if ( fLiveAtoms.count(&atom) == 0 ) {
+               // if -whylive cares about this symbol, then dump chain
+               if ( (previous->name != NULL) && fOptions.printWhyLive(previous->name) ) {
+                       int depth = 0;
+                       for(WhyLiveBackChain* p = previous; p != NULL; p = p->previous, ++depth) {
+                               for(int i=depth; i > 0; --i)
+                                       fprintf(stderr, "  ");
+                               fprintf(stderr, "%s\n", p->name);
+                       }
+               }
+               // set up next chain
+               WhyLiveBackChain thisChain;
+               thisChain.previous = previous;
                // this atom is live
-               liveAtoms.insert(atom);
-               // so don't dead strip
-               atom->setDontDeadStrip();
-
+               fLiveAtoms.insert(&atom);
                // and all atoms it references
-               std::vector<class ObjectFile::Reference*>& references = atom->getReferences();
+               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);
+                       if ( reference->isTargetUnbound() ) {
+                               // look in global symbol table
+                               const char* targetName = reference->getTargetName();
+                               ObjectFile::Atom* target = fGlobalSymbolTable.find(targetName);
+                               if ( target == NULL ) {
+                                       // load archives or dylibs
+                                       this->addJustInTimeAtoms(targetName);
+                               }
+                               // look again
+                               target = fGlobalSymbolTable.find(targetName);
+                               if ( target != NULL ) {
+                                       reference->setTarget(*target, reference->getTargetOffset());
+                               }
+                               else {
+                                       // mark as undefined, for later error processing
+                                       fGlobalSymbolTable.require(targetName);
+                               }
+                       }
+                       if ( ! reference->isTargetUnbound() ) {
+                               thisChain.name = reference->getTargetName();
+                               markLive(reference->getTarget(), &thisChain);
+                       }
+                       if ( reference->hasFromTarget() ) {
+                               // do the same as above, for from target
+                               if ( reference->isFromTargetUnbound() ) {
+                                       // look in global symbol table
+                                       const char* targetName = reference->getFromTargetName();
+                                       ObjectFile::Atom* target = fGlobalSymbolTable.find(targetName);
+                                       if ( target == NULL ) {
+                                               // load archives or dylibs
+                                               this->addJustInTimeAtoms(targetName);
+                                       }
+                                       // look again
+                                       target = fGlobalSymbolTable.find(targetName);
+                                       if ( target != NULL ) {
+                                               reference->setFromTarget(*target);
+                                       }
+                                       else {
+                                               // mark as undefined, for later error processing
+                                               fGlobalSymbolTable.require(targetName);
+                                       }
+                               }
+                               if ( ! reference->isFromTargetUnbound() ) {
+                                       thisChain.name = reference->getFromTargetName();
+                                       markLive(reference->getFromTarget(), &thisChain);
+                               }
+                       }
                }
        }
 }
 
-void Linker::deadStrip()
+
+void Linker::addLiveRoot(const char* name)
+{
+       ObjectFile::Atom* target = fGlobalSymbolTable.find(name);
+       if ( target == NULL ) {
+               this->addJustInTimeAtoms(name);
+               target = fGlobalSymbolTable.find(name);
+       }
+       if ( target != NULL )
+               fLiveRootAtoms.insert(target);
+}
+
+
+void Linker::deadStripResolve()
 {
-       if ( fOptions.deadStrip() != Options::kDeadStripOff ) {
-               std::set<ObjectFile::Atom*> liveAtoms;
+       // add main() to live roots
+       ObjectFile::Atom* entryPoint = this->entryPoint();
+       if ( entryPoint != NULL )
+               fLiveRootAtoms.insert(entryPoint);
 
-               // mark main() and all atoms reachable from it as live
-               ObjectFile::Atom* entryPoint = this->entryPoint();
-               if ( entryPoint != NULL )
-                       markLive(entryPoint, liveAtoms);
+       // add dyld_stub_binding_helper() to live roots
+       ObjectFile::Atom* dyldHelper = this->dyldHelper();
+       if ( dyldHelper != NULL )
+               fLiveRootAtoms.insert(dyldHelper);
 
-               ObjectFile::Atom* dyldHelper = this->dyldHelper();
-               if ( dyldHelper != NULL )
-                       markLive(dyldHelper, liveAtoms);
+       // add -exported_symbols_list, -init, and -u entries to live roots
+       std::vector<const char*>& initialUndefines = fOptions.initialUndefines();
+       for (std::vector<const char*>::iterator it=initialUndefines.begin(); it != initialUndefines.end(); it++)
+               addLiveRoot(*it);
 
-               // 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 );
+       // in some cases, every global scope atom in initial .o files is a root
+       if ( fOptions.allGlobalsAreDeadStripRoots() ) {
                for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
                        ObjectFile::Atom* atom = *it;
-                       //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);
+                       if ( atom->getScope() == ObjectFile::Atom::scopeGlobal )
+                               fLiveRootAtoms.insert(atom);
                }
-
-               // 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());
-               //}
 
-               // 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());
+       // mark all roots as live, and all atoms they reference
+       for (std::set<ObjectFile::Atom*>::iterator it=fLiveRootAtoms.begin(); it != fLiveRootAtoms.end(); it++) {
+               WhyLiveBackChain rootChain;
+               rootChain.previous = NULL;
+               rootChain.name = (*it)->getDisplayName();
+               markLive(**it, &rootChain);
        }
-}
-
 
+       // now remove all non-live atoms from fAllAtoms
+       fAllAtoms.erase(std::remove_if(fAllAtoms.begin(), fAllAtoms.end(), NotLive(fLiveAtoms)), fAllAtoms.end());
+}
 
 void Linker::sortAtoms()
 {
@@ -978,18 +1128,9 @@ void Linker::writeDotOutput()
                                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);
+                                               fprintf(out, "\taddr%p [ shape = plaintext, label = \"%s\" ];\n", atom, name);
                                        }
                                        else if ( strcmp(atom->getSectionName(), "__cstring") == 0 ) {
                                                char cstring[atom->getSize()+2];
@@ -1021,37 +1162,7 @@ void Linker::writeDotOutput()
                                                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, "\taddr%p -> addr%p;\n", fromAtom, toAtom);
                                                }
                                        }
                                }
@@ -1065,11 +1176,7 @@ void Linker::writeDotOutput()
                                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, "addr%p; ", atom);
                                        }
                        }
                        fprintf(out, "};\n ");
@@ -1094,14 +1201,14 @@ ObjectFile::Atom* Linker::entryPoint()
                case Options::kDyld:
                        entryPoint = fGlobalSymbolTable.find(fOptions.entryName());
                        if ( entryPoint == NULL ) {
-                               throwf("could not find entry point: %s", fOptions.entryName());
+                               throwf("could not find entry point \"%s\" (perhaps missing crt1.o)", fOptions.entryName());
                        }
                        break;
                case Options::kDynamicLibrary:
                        if ( fOptions.initFunctionName() != NULL ) {
                                entryPoint = fGlobalSymbolTable.find(fOptions.initFunctionName());
                                if ( entryPoint == NULL ) {
-                                       throwf("could not find -init function: %s", fOptions.initFunctionName());
+                                       throwf("could not find -init function: \"%s\"", fOptions.initFunctionName());
                                }
                        }
                        break;
@@ -1136,7 +1243,7 @@ const char* Linker::assureFullPath(const char* path)
 //
 // The stab strings are of the form:
 //             <name> ':' <type-code> <number-pari>
-//  but the <name> contain a colon. 
+//  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) )
 //
@@ -1200,8 +1307,9 @@ bool Linker::minimizeStab(ObjectFile::Reader::Stab& stab)
        }
 }
 
-struct HeaderRange { 
-       std::vector<ObjectFile::Reader::Stab>::iterator begin; 
+
+struct HeaderRange {
+       std::vector<ObjectFile::Reader::Stab>::iterator begin;
        std::vector<ObjectFile::Reader::Stab>::iterator end;
        int                                                                                             parentRangeIndex;
        uint32_t                                                                                sum;
@@ -1217,19 +1325,25 @@ typedef __gnu_cxx::hash_map<const char*, std::vector<uint32_t>, __gnu_cxx::hash<
 static PathToSums sKnownBINCLs;
 
 
-void Linker::collectStabs(ObjectFile::Reader* reader)
+void Linker::collectStabs(ObjectFile::Reader* reader, std::map<class ObjectFile::Atom*, uint32_t>& atomOrdinals)
 {
        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;
+       ObjectFile::Atom* atomWithLowestOrdinal = NULL;
+       ObjectFile::Atom* atomWithHighestOrdinal = NULL;
+       uint32_t highestOrdinal = 0;
+       uint32_t lowestOrdinal = UINT_MAX;
+       std::vector<std::pair<ObjectFile::Atom*,ObjectFile::Atom*> > soRanges;
+       // 1) find all (possibly nested) BINCL/EINCL ranges and their checksums
+       // 2) find all SO/SO ranges and the first/last atom own by a FUN stab therein
        for(std::vector<class ObjectFile::Reader::Stab>::iterator it=readerStabs->begin(); it != readerStabs->end(); ++it) {
                ++count;
                switch ( it->type ) {
@@ -1239,7 +1353,7 @@ void Linker::collectStabs(ObjectFile::Reader* reader)
                                        range.begin = it;
                                        range.end = readerStabs->end();
                                        range.parentRangeIndex = curRangeIndex;
-                                       range.sum = it->value; 
+                                       range.sum = it->value;
                                        range.sumPrecomputed = (range.sum != 0);
                                        range.useEXCL = false;
                                        range.cannotEXCL = false;
@@ -1257,8 +1371,23 @@ void Linker::collectStabs(ObjectFile::Reader* reader)
                                        if ( log ) fprintf(stderr, "[%d->%d]EINCL %s\n", curRangeIndex, ranges[curRangeIndex].parentRangeIndex, it->string);
                                        curRangeIndex = ranges[curRangeIndex].parentRangeIndex;
                                }
-                               break;                          
+                               break;
                        case N_FUN:
+                               {
+                                       std::map<class ObjectFile::Atom*, uint32_t>::iterator pos = atomOrdinals.find(it->atom);
+                                       if ( pos != atomOrdinals.end() ) {
+                                               uint32_t ordinal = pos->second;
+                                               if ( ordinal > highestOrdinal ) {
+                                                       highestOrdinal = ordinal;
+                                                       atomWithHighestOrdinal = it->atom;
+                                               }
+                                               if ( ordinal < lowestOrdinal ) {
+                                                       lowestOrdinal = ordinal;
+                                                       atomWithLowestOrdinal = it->atom;
+                                               }
+                                       }
+                               }
+                               // fall through
                        case N_BNSYM:
                        case N_ENSYM:
                        case N_LBRAC:
@@ -1272,6 +1401,19 @@ void Linker::collectStabs(ObjectFile::Reader* reader)
                                                fprintf(stderr, "ld64: cannot do BINCL/EINCL optimzation because of stabs kinds in %s for %s\n", ranges[curRangeIndex].begin->string, reader->getPath());
                                }
                                break;
+                       case N_SO:
+                               if ( (it->string != NULL) && (strlen(it->string) > 0) ) {
+                                       // start SO, reset hi/low FUN tracking
+                                       atomWithLowestOrdinal = NULL;
+                                       atomWithHighestOrdinal = NULL;
+                                       highestOrdinal = 0;
+                                       lowestOrdinal = UINT_MAX;
+                               }
+                               else {
+                                       // end SO, record hi/low atoms for this SO range
+                                       soRanges.push_back(std::make_pair<ObjectFile::Atom*,ObjectFile::Atom*>(atomWithLowestOrdinal, atomWithHighestOrdinal));
+                               }
+                               // fall through
                        default:
                                if ( curRangeIndex != -1 ) {
                                        if ( ! ranges[curRangeIndex].sumPrecomputed ) {
@@ -1289,34 +1431,42 @@ void Linker::collectStabs(ObjectFile::Reader* reader)
                                                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);
+               int soIndex = 0;
+               for(std::vector<ObjectFile::Reader::Stab>::iterator it=readerStabs->begin(); it != readerStabs->end(); ++it) {
+                       // copy minimal or all stabs
+                       ObjectFile::Reader::Stab stab = *it;
+                       if ( !minimal || minimizeStab(stab) ) {
+                               if ( stab.type == N_SO ) {
+                                       if ( (stab.string != NULL) && (strlen(stab.string) > 0) ) {
+                                               // starting SO is associated with first atom
+                                               stab.atom = soRanges[soIndex].first;
+                                       }
+                                       else {
+                                               // ending SO is associated with last atom
+                                               stab.atom = soRanges[soIndex].second;
+                                               ++soIndex;
+                                       }
+                               }
+                               fStabs.push_back(stab);
                        }
                }
-               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);
        //}
-       
+
        // 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 ) {
@@ -1347,10 +1497,11 @@ void Linker::collectStabs(ObjectFile::Reader* reader)
                        }
                }
        }
-       
+
        // add a new set of stabs with BINCL/EINCL runs that have been seen before, replaced with EXCLs
        curRangeIndex = -1;
        const int maxRangeIndex = ranges.size();
+       int soIndex = 0;
        for(std::vector<ObjectFile::Reader::Stab>::iterator it=readerStabs->begin(); it != readerStabs->end(); ++it) {
                switch ( it->type ) {
                        case N_BINCL:
@@ -1360,7 +1511,7 @@ void Linker::collectStabs(ObjectFile::Reader* reader)
                                                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 ) 
+                                               if ( range.useEXCL )
                                                        stab.type = N_EXCL;     // transform BINCL into EXCL
                                                if ( !minimal )
                                                        fStabs.push_back(stab);
@@ -1374,11 +1525,24 @@ void Linker::collectStabs(ObjectFile::Reader* reader)
                                                fStabs.push_back(*it);
                                        curRangeIndex = ranges[curRangeIndex].parentRangeIndex;
                                }
-                               break;                          
+                               break;
                        default:
                                if ( (curRangeIndex == -1) || !ranges[curRangeIndex].useEXCL ) {
-                                       if ( !minimal || minimizeStab(*it) )
-                                               fStabs.push_back(*it);
+                                       ObjectFile::Reader::Stab stab = *it;
+                                       if ( !minimal || minimizeStab(stab) ) {
+                                               if ( stab.type == N_SO ) {
+                                                       if ( (stab.string != NULL) || (strlen(stab.string) > 0) ) {
+                                                               // starting SO is associated with first atom
+                                                               stab.atom = soRanges[soIndex].first;
+                                                       }
+                                                       else {
+                                                               // ending SO is associated with last atom
+                                                               stab.atom = soRanges[soIndex].second;
+                                                               ++soIndex;
+                                                       }
+                                               }
+                                               fStabs.push_back(stab);
+                                       }
                                }
                }
        }
@@ -1397,10 +1561,13 @@ void Linker::synthesizeStabs(ObjectFile::Reader* reader)
                ObjectFile::Atom* atom = *it;
                if ( atom->getFile() == reader ) {
                        const char* name = atom->getName();
-                       if ( (name != NULL) && (name[0] == '_' ) && (atom->getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn) ) {
+                       if ( (name != NULL) && (atom->getSymbolTableInclusion() != ObjectFile::Atom::kSymbolTableNotIn) ) {
                                const char* newDirPath;
                                const char* newFilename;
                                if ( atom->getTranslationUnitSource(&newDirPath, &newFilename) ) {
+                                       // gdb like directory SO's to end in '/', but dwarf DW_AT_comp_dir usually does not have trailing '/'
+                                       if ( (newDirPath != NULL) && (strlen(newDirPath) > 1 ) && (newDirPath[strlen(newDirPath)-1] != '/') )
+                                               asprintf((char**)&newDirPath, "%s/", newDirPath);
                                        // need SO's whenever the translation unit source file changes
                                        if ( newFilename != filename ) {
                                                if ( filename != NULL ) {
@@ -1559,6 +1726,14 @@ void Linker::synthesizeStabs(ObjectFile::Reader* reader)
 void Linker::collectStabs()
 {
        if ( fOptions.readerOptions().fDebugInfoStripping != ObjectFile::ReaderOptions::kDebugInfoNone ) {
+
+               // make mapping from atoms to ordinal
+               std::map<class ObjectFile::Atom*, uint32_t>     atomOrdinals;
+               uint32_t ordinal = 1;
+               for (std::vector<ObjectFile::Atom*>::iterator it=fAllAtoms.begin(); it != fAllAtoms.end(); it++) {
+                       atomOrdinals[*it] = ordinal++;
+               }
+
                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();
@@ -1571,14 +1746,14 @@ void Linker::collectStabs()
                                                // do nothing
                                                break;
                                        case ObjectFile::Reader::kDebugInfoStabs:
-                                               collectStabs(reader);
+                                               collectStabs(reader, atomOrdinals);
                                                break;
                                        case ObjectFile::Reader::kDebugInfoDwarf:
                                                synthesizeStabs(reader);
                                                fCreateUUID = true;
                                                break;
                                    case ObjectFile::Reader::kDebugInfoStabsUUID:
-                                               collectStabs(reader);
+                                               collectStabs(reader, atomOrdinals);
                                                fCreateUUID = true;
                                                break;
                                        default:
@@ -1645,44 +1820,40 @@ ObjectFile::Reader* Linker::createReader(const Options::FileInfo& info)
                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::dylib::Reader<ppc>::validFile(p, info.options.fBundleLoader) )
+                               return this->addDylib(mach_o::dylib::Reader<ppc>::make(p, len, info.path, info.options.fBundleLoader, 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::dylib::Reader<ppc64>::validFile(p, info.options.fBundleLoader) )
+                               return this->addDylib(mach_o::dylib::Reader<ppc64>::make(p, len, info.path, info.options.fBundleLoader, 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::dylib::Reader<x86>::validFile(p, info.options.fBundleLoader) )
+                               return this->addDylib(mach_o::dylib::Reader<x86>::make(p, len, info.path, info.options.fBundleLoader, 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;
+               case CPU_TYPE_X86_64:
+                       if ( mach_o::relocatable::Reader<x86_64>::validFile(p) )
+                               return this->addObject(mach_o::relocatable::Reader<x86_64>::make(p, info.path, info.modTime, fOptions.readerOptions()), info, len);
+                       else if ( mach_o::dylib::Reader<x86_64>::validFile(p, info.options.fBundleLoader) )
+                               return this->addDylib(mach_o::dylib::Reader<x86_64>::make(p, len, info.path, info.options.fBundleLoader, fOptions.readerOptions()), info, len);
+                       else if ( mach_o::archive::Reader<x86_64>::validFile(p, len) )
+                               return this->addArchive(mach_o::archive::Reader<x86_64>::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 (fArchitecture) {
-                       case CPU_TYPE_POWERPC:
-                               archName = "ppc";
-                               break;
-                       case CPU_TYPE_POWERPC64:
-                               archName = "ppc64";
-                               break;
-                       case CPU_TYPE_I386:
-                               archName = "i386";
-                               break;
-               }
-               throwf("missing required architecture %s in fat file", archName);
+               throwf("missing required architecture %s in file", fArchitectureName);
        }
        else {
                throw "file is not of required architecture";
@@ -1847,7 +2018,7 @@ ObjectFile::Reader* Linker::addObject(ObjectFile::Reader* reader, const Options:
 
 ObjectFile::Reader* Linker::addDylib(ObjectFile::Reader* reader, const Options::FileInfo& info, uint64_t mappedLen)
 {
-       if ( reader->getInstallPath() == NULL ) {
+       if ( (reader->getInstallPath() == NULL) && !info.options.fBundleLoader ) {
                // this is a "blank" stub
                // silently ignore it
                return reader;
@@ -1870,7 +2041,7 @@ ObjectFile::Reader* Linker::addDylib(ObjectFile::Reader* reader, const 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;
@@ -1880,11 +2051,11 @@ ObjectFile::Reader* Linker::addDylib(ObjectFile::Reader* reader, const Options::
                        // 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) 
+                       okToLink = ( (outputFilePathLastSlash != NULL)
+                                       && (fOptions.umbrellaName() != NULL)
                                        && (strcmp(fOptions.umbrellaName(), reader->parentUmbrella()) == 0) );
                }
 
@@ -1912,21 +2083,21 @@ ObjectFile::Reader* Linker::addDylib(ObjectFile::Reader* reader, const Options::
                                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;
 
@@ -2040,6 +2211,9 @@ void Linker::createWriter()
                case CPU_TYPE_I386:
                        this->setOutputFile(new mach_o::executable::Writer<x86>(path, fOptions, fDynamicLibraries));
                        break;
+               case CPU_TYPE_X86_64:
+                       this->setOutputFile(new mach_o::executable::Writer<x86_64>(path, fOptions, fDynamicLibraries));
+                       break;
                default:
                        throw "unknown architecture";
        }
@@ -2292,10 +2466,18 @@ bool Linker::AtomSorter::operator()(ObjectFile::Atom* left, ObjectFile::Atom* ri
 
 int main(int argc, const char* argv[])
 {
+       const char* archName = NULL;
+       bool showArch = false;
+       bool archInferred = false;
        try {
                // create linker object given command line arguments
                Linker ld(argc, argv);
 
+               // save error message prefix
+               archName = ld.architectureName();
+               archInferred = ld.isInferredArchitecture();
+               showArch = ld.showArchitectureInErrors();
+
                // open all input files
                ld.createReaders();
 
@@ -2306,10 +2488,15 @@ int main(int argc, const char* argv[])
                ld.link();
        }
        catch (const char* msg) {
-               fprintf(stderr, "ld64 failed: %s\n", msg);
+               extern const double ld64VersionNumber;
+               if ( archInferred )
+                       fprintf(stderr, "ld64-%g failed: %s for inferred architecture %s\n", ld64VersionNumber, msg, archName);
+               else if ( showArch )
+                       fprintf(stderr, "ld64-%g failed: %s for architecture %s\n", ld64VersionNumber, msg, archName);
+               else
+                       fprintf(stderr, "ld64-%g failed: %s\n", ld64VersionNumber, msg);
                return 1;
        }
 
-
        return 0;
 }
index 55f9fd9bfe87e49aec48de44c80050550b1621aa..118aa497da57c7b8b18be16b3c3d7720ae8c1363 100644 (file)
@@ -32,6 +32,9 @@
 #include <mach-o/loader.h>
 #include <mach-o/fat.h>
 #include <mach-o/stab.h>
+#include <mach-o/reloc.h>
+#include <mach-o/ppc/reloc.h>
+#include <mach-o/x86_64/reloc.h>
 
 #include <vector>
 
@@ -74,6 +77,11 @@ private:
        void                                                                            checkSection(const macho_segment_command<P>* segCmd, const macho_section<P>* sect);
        uint8_t                                                                         loadCommandSizeMask();
        void                                                                            checkIndirectSymbolTable();
+       void                                                                            checkRelocations();
+       void                                                                            checkExternalReloation(const macho_relocation_info<P>* reloc);
+       void                                                                            checkLocalReloation(const macho_relocation_info<P>* reloc);
+       pint_t                                                                          relocBase();
+       bool                                                                            addressInWritableSegment(pint_t address);
 
        const char*                                                                     fPath;
        const macho_header<P>*                                          fHeader;
@@ -84,7 +92,14 @@ private:
        uint32_t                                                                        fSymbolCount;
        const uint32_t*                                                         fIndirectTable;
        uint32_t                                                                        fIndirectTableCount;
-
+       const macho_relocation_info<P>*                         fLocalRelocations;
+       uint32_t                                                                        fLocalRelocationsCount;
+       const macho_relocation_info<P>*                         fExternalRelocations;
+       uint32_t                                                                        fExternalRelocationsCount;
+       pint_t                                                                          fRelocBase;
+       bool                                                                            fWriteableSegmentWithAddrOver4G;
+       const macho_segment_command<P>*                         fFirstSegment;
+       const macho_segment_command<P>*                         fFirstWritableSegment;
 };
 
 
@@ -143,16 +158,36 @@ bool MachOChecker<x86>::validFile(const uint8_t* fileContent)
        return false;
 }
 
+template <>
+bool MachOChecker<x86_64>::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_X86_64 )
+               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 <> uint8_t MachOChecker<x86_64>::loadCommandSizeMask() { return 0x07; }
 
 
 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)
+ : fHeader(NULL), fLength(fileLength), fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fIndirectTableCount(0),
+ fLocalRelocations(NULL),  fLocalRelocationsCount(0),  fExternalRelocations(NULL),  fExternalRelocationsCount(0),
+ fRelocBase(0), fWriteableSegmentWithAddrOver4G(false), fFirstSegment(NULL), fFirstWritableSegment(NULL)
 {
        // sanity check
        if ( ! validFile(fileContent) )
@@ -169,6 +204,7 @@ MachOChecker<A>::MachOChecker(const uint8_t* fileContent, uint32_t fileLength, c
        
        checkIndirectSymbolTable();
 
+       checkRelocations();
 }
 
 
@@ -284,6 +320,12 @@ void MachOChecker<A>::checkLoadCommands()
                        // keep LINKEDIT segment 
                        if ( strcmp(segCmd->segname(), "__LINKEDIT") == 0 )
                                linkEditSegment = segCmd;
+
+                       // cache interesting segments
+                       if ( fFirstSegment == NULL )
+                               fFirstSegment = segCmd;
+                       if ( (fFirstWritableSegment == NULL) && ((segCmd->initprot() & VM_PROT_WRITE) != 0) )
+                               fFirstWritableSegment = segCmd;
                                
                        // check section ranges
                        const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
@@ -364,6 +406,22 @@ void MachOChecker<A>::checkLoadCommands()
                                                throw "indirect symbol table not in __LINKEDIT";
                                        if ( (dsymtab->indirectsymoff()+fIndirectTableCount*8) > (linkEditSegment->fileoff()+linkEditSegment->filesize()) )
                                                throw "indirect symbol table not in __LINKEDIT";
+                                       fLocalRelocationsCount = dsymtab->nlocrel();
+                                       if ( fLocalRelocationsCount != 0 ) {
+                                               fLocalRelocations = (const macho_relocation_info<P>*)((char*)fHeader + dsymtab->locreloff());
+                                               if ( dsymtab->locreloff() < linkEditSegment->fileoff() )
+                                                       throw "local relocations not in __LINKEDIT";
+                                               if ( (dsymtab->locreloff()+fLocalRelocationsCount*sizeof(macho_relocation_info<P>)) > (linkEditSegment->fileoff()+linkEditSegment->filesize()) )
+                                                       throw "local relocations not in __LINKEDIT";
+                                       }
+                                       fExternalRelocationsCount = dsymtab->nextrel();
+                                       if ( fExternalRelocationsCount != 0 ) {
+                                               fExternalRelocations = (const macho_relocation_info<P>*)((char*)fHeader + dsymtab->extreloff());
+                                               if ( dsymtab->extreloff() < linkEditSegment->fileoff() )
+                                                       throw "local relocations not in __LINKEDIT";
+                                               if ( (dsymtab->extreloff()+fExternalRelocationsCount*sizeof(macho_relocation_info<P>)) > (linkEditSegment->fileoff()+linkEditSegment->filesize()) )
+                                                       throw "local relocations not in __LINKEDIT";
+                                       }
                                }
                                break;
                }
@@ -374,7 +432,7 @@ void MachOChecker<A>::checkLoadCommands()
        if ( fStrings == NULL )
                throw "missing symbol table";
        
-       
+       fRelocBase = this->relocBase();
        
 }
 
@@ -430,6 +488,177 @@ void MachOChecker<A>::checkIndirectSymbolTable()
 }
 
 
+
+template <>
+ppc::P::uint_t MachOChecker<ppc>::relocBase()
+{
+       if ( fHeader->flags() & MH_SPLIT_SEGS )
+               return fFirstWritableSegment->vmaddr();
+       else
+               return fFirstSegment->vmaddr();
+}
+
+template <>
+ppc64::P::uint_t MachOChecker<ppc64>::relocBase()
+{
+       if ( fWriteableSegmentWithAddrOver4G ) 
+               return fFirstWritableSegment->vmaddr();
+       else
+               return fFirstSegment->vmaddr();
+}
+
+template <>
+x86::P::uint_t MachOChecker<x86>::relocBase()
+{
+       if ( fHeader->flags() & MH_SPLIT_SEGS )
+               return fFirstWritableSegment->vmaddr();
+       else
+               return fFirstSegment->vmaddr();
+}
+
+template <>
+x86_64::P::uint_t MachOChecker<x86_64>::relocBase()
+{
+       // check for split-seg
+       return fFirstWritableSegment->vmaddr();
+}
+
+
+template <typename A>
+bool MachOChecker<A>::addressInWritableSegment(pint_t address)
+{
+       const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
+       const uint32_t cmd_count = fHeader->ncmds();
+       const macho_load_command<P>* cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
+                       const macho_segment_command<P>* segCmd = (const macho_segment_command<P>*)cmd;
+                       if ( (segCmd->initprot() & VM_PROT_WRITE) != 0 ) {
+                               if ( (address >= segCmd->vmaddr()) && (address < segCmd->vmaddr()+segCmd->vmsize()) )
+                                       return true;
+                       }
+               }
+               cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+       }
+       return false;
+}
+
+
+template <>
+void MachOChecker<ppc>::checkExternalReloation(const macho_relocation_info<P>* reloc)
+{
+       // FIX
+}
+
+template <>
+void MachOChecker<ppc64>::checkExternalReloation(const macho_relocation_info<P>* reloc)
+{
+       if ( reloc->r_length() != 3 ) 
+               throw "bad external relocation length";
+       if ( reloc->r_type() != GENERIC_RELOC_VANILLA ) 
+               throw "unknown external relocation type";
+       if ( reloc->r_pcrel() != 0 ) 
+               throw "bad external relocation pc_rel";
+       if ( reloc->r_extern() == 0 )
+               throw "local relocation found with external relocations";
+       if ( ! this->addressInWritableSegment(reloc->r_address() + this->relocBase()) )
+               throw "local relocation address not in writable segment";
+       // FIX: check r_symbol
+}
+
+template <>
+void MachOChecker<x86>::checkExternalReloation(const macho_relocation_info<P>* reloc)
+{
+       // FIX
+}
+
+
+template <>
+void MachOChecker<x86_64>::checkExternalReloation(const macho_relocation_info<P>* reloc)
+{
+       if ( reloc->r_length() != 3 ) 
+               throw "bad external relocation length";
+       if ( reloc->r_type() != X86_64_RELOC_UNSIGNED ) 
+               throw "unknown external relocation type";
+       if ( reloc->r_pcrel() != 0 ) 
+               throw "bad external relocation pc_rel";
+       if ( reloc->r_extern() == 0 ) 
+               throw "local relocation found with external relocations";
+       if ( ! this->addressInWritableSegment(reloc->r_address() + this->relocBase()) )
+               throw "exernal relocation address not in writable segment";
+       // FIX: check r_symbol
+}
+
+template <>
+void MachOChecker<ppc>::checkLocalReloation(const macho_relocation_info<P>* reloc)
+{
+       if ( reloc->r_address() & R_SCATTERED ) {
+               // scattered
+               const macho_scattered_relocation_info<P>* sreloc = (const macho_scattered_relocation_info<P>*)reloc;
+               // FIX
+       
+       }
+       else {
+               // FIX
+               if ( ! this->addressInWritableSegment(reloc->r_address() + this->relocBase()) )
+                       throw "local relocation address not in writable segment";
+       }
+}
+
+
+template <>
+void MachOChecker<ppc64>::checkLocalReloation(const macho_relocation_info<P>* reloc)
+{
+       if ( reloc->r_length() != 3 ) 
+               throw "bad local relocation length";
+       if ( reloc->r_type() != GENERIC_RELOC_VANILLA ) 
+               throw "unknown local relocation type";
+       if ( reloc->r_pcrel() != 0 ) 
+               throw "bad local relocation pc_rel";
+       if ( reloc->r_extern() != 0 ) 
+               throw "external relocation found with local relocations";
+       if ( ! this->addressInWritableSegment(reloc->r_address() + this->relocBase()) )
+               throw "local relocation address not in writable segment";
+}
+
+template <>
+void MachOChecker<x86>::checkLocalReloation(const macho_relocation_info<P>* reloc)
+{
+       // FIX
+}
+
+template <>
+void MachOChecker<x86_64>::checkLocalReloation(const macho_relocation_info<P>* reloc)
+{
+       if ( reloc->r_length() != 3 ) 
+               throw "bad local relocation length";
+       if ( reloc->r_type() != X86_64_RELOC_UNSIGNED ) 
+               throw "unknown local relocation type";
+       if ( reloc->r_pcrel() != 0 ) 
+               throw "bad local relocation pc_rel";
+       if ( reloc->r_extern() != 0 ) 
+               throw "external relocation found with local relocations";
+       if ( ! this->addressInWritableSegment(reloc->r_address() + this->relocBase()) )
+               throw "local relocation address not in writable segment";
+}
+
+
+
+template <typename A>
+void MachOChecker<A>::checkRelocations()
+{
+       const macho_relocation_info<P>* const externRelocsEnd = &fExternalRelocations[fExternalRelocationsCount];
+       for (const macho_relocation_info<P>* reloc = fExternalRelocations; reloc < externRelocsEnd; ++reloc) {
+               this->checkExternalReloation(reloc);
+       }
+       
+       const macho_relocation_info<P>* const localRelocsEnd = &fLocalRelocations[fLocalRelocationsCount];
+       for (const macho_relocation_info<P>* reloc = fLocalRelocations; reloc < localRelocsEnd; ++reloc) {
+               this->checkLocalReloation(reloc);
+       }
+}
+
+
 static void check(const char* path)
 {
        struct stat stat_buf;
@@ -440,7 +669,9 @@ static void check(const char* path)
                        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);
+               uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
+               if ( p == ((uint8_t*)(-1)) )
+                       throw "cannot map file";
                ::close(fd);
                const mach_header* mh = (mach_header*)p;
                if ( mh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
@@ -465,6 +696,12 @@ static void check(const char* path)
                                        else
                                                throw "in universal file, ppc64 slice does not contain ppc64 mach-o";
                                }
+                               else if ( archs[i].cputype == CPU_TYPE_X86_64 ) {
+                                       if ( MachOChecker<x86_64>::validFile(p + archs[i].offset) )
+                                               MachOChecker<x86_64>::make(p + archs[i].offset, archs[i].size, path);
+                                       else
+                                               throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
+                               }
                                else {
                                                throw "in universal file, unknown architecture slice";
                                }
@@ -479,6 +716,9 @@ static void check(const char* path)
                else if ( MachOChecker<ppc64>::validFile(p) ) {
                        MachOChecker<ppc64>::make(p, length, path);
                }
+               else if ( MachOChecker<x86_64>::validFile(p) ) {
+                       MachOChecker<x86_64>::make(p, length, path);
+               }
                else {
                        throw "not a known file type";
                }
diff --git a/src/rebase.cpp b/src/rebase.cpp
new file mode 100644 (file)
index 0000000..ab62f9b
--- /dev/null
@@ -0,0 +1,907 @@
+/* -*- 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 <mach/mach.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <mach-o/loader.h>
+#include <mach-o/fat.h>
+#include <mach-o/reloc.h>
+#include <mach-o/ppc/reloc.h>
+#include <mach-o/x86_64/reloc.h>
+#include <vector>
+#include <set>
+
+#include "MachOFileAbstraction.hpp"
+#include "Architectures.hpp"
+
+
+static bool verbose = false;
+
+__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;
+}
+
+
+class AbstractRebaser
+{
+public:
+       virtual cpu_type_t                                                      getArchitecture() const = 0;
+       virtual uint64_t                                                        getBaseAddress() const = 0;
+       virtual uint64_t                                                        getVMSize() const = 0;
+       virtual void                                                            setBaseAddress(uint64_t) = 0;
+};
+
+
+template <typename A>
+class Rebaser : public AbstractRebaser
+{
+public:
+                                                                                               Rebaser(const void* machHeader);
+       virtual                                                                         ~Rebaser() {}
+
+       virtual cpu_type_t                                                      getArchitecture() const;
+       virtual uint64_t                                                        getBaseAddress() const;
+       virtual uint64_t                                                        getVMSize() const;
+       virtual void                                                            setBaseAddress(uint64_t);
+
+private:
+       typedef typename A::P                                   P;
+       typedef typename A::P::E                                E;
+       typedef typename A::P::uint_t                   pint_t;
+       
+       struct vmmap { pint_t vmaddr; pint_t vmsize; pint_t fileoff; };
+       
+       void                                                                            setRelocBase();
+       void                                                                            buildSectionTable();
+       void                                                                            adjustLoadCommands();
+       void                                                                            adjustSymbolTable();
+       void                                                                            adjustDATA();
+       void                                                                            doLocalRelocation(const macho_relocation_info<P>* reloc);
+       pint_t*                                                                         mappedAddressForVMAddress(uint32_t vmaddress);
+       
+       const macho_header<P>*                                          fHeader;
+       pint_t                                                                          fOrignalVMRelocBaseAddress;
+       pint_t                                                                          fSlide;
+       pint_t                                                                          fRelocBase;
+       std::vector<vmmap>                                                      fVMMApping;
+};
+
+
+
+class MultiArchRebaser
+{
+public:
+                                                                                               MultiArchRebaser(const char* path, bool writable=false);
+                                                                                               ~MultiArchRebaser();
+
+       const std::vector<AbstractRebaser*>&            getArchs() const { return fRebasers; }
+       void                                                                            commit();
+
+private:
+       std::vector<AbstractRebaser*>                           fRebasers;
+       void*                                                                           fMappingAddress;
+       uint64_t                                                                        fFileSize;
+};
+
+
+
+MultiArchRebaser::MultiArchRebaser(const char* path, bool writable)
+ : fMappingAddress(0), fFileSize(0)
+{
+       // map in whole file
+       int fd = ::open(path, (writable ? O_RDWR : O_RDONLY), 0);
+       if ( fd == -1 )
+               throwf("can't open file, errno=%d", errno);
+       struct stat stat_buf;
+       if ( fstat(fd, &stat_buf) == -1)
+               throwf("can't stat open file %s, errno=%d", path, errno);
+       if ( stat_buf.st_size < 20 )
+               throwf("file too small %s", path);
+       const int prot = writable ? (PROT_READ | PROT_WRITE) : PROT_READ;
+       const int flags = writable ? (MAP_FILE | MAP_SHARED) : (MAP_FILE | MAP_PRIVATE);
+       uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, prot, flags, fd, 0);
+       if ( p == (uint8_t*)(-1) )
+               throwf("can't map file %s, errno=%d", path, errno);
+       ::close(fd);
+
+       // if fat file, process each architecture
+       const fat_header* fh = (fat_header*)p;
+       const mach_header* mh = (mach_header*)p;
+       if ( fh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
+               // Fat header is always big-endian
+               const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
+               for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
+                       uint32_t fileOffset = OSSwapBigToHostInt32(archs[i].offset);
+                       try {
+                               switch ( OSSwapBigToHostInt32(archs[i].cputype) ) {
+                                       case CPU_TYPE_POWERPC:
+                                               fRebasers.push_back(new Rebaser<ppc>(&p[fileOffset]));
+                                               break;
+                                       case CPU_TYPE_POWERPC64:
+                                               fRebasers.push_back(new Rebaser<ppc64>(&p[fileOffset]));
+                                               break;
+                                       case CPU_TYPE_I386:
+                                               fRebasers.push_back(new Rebaser<x86>(&p[fileOffset]));
+                                               break;
+                                       case CPU_TYPE_X86_64:
+                                               fRebasers.push_back(new Rebaser<x86_64>(&p[fileOffset]));
+                                               break;
+                                       default:
+                                               throw "unknown file format";
+                               }
+                       }
+                       catch (const char* msg) {
+                               fprintf(stderr, "rebase warning: %s for %s\n", msg, path);
+                       }
+               }
+       }
+       else {
+               try {
+                       if ( (OSSwapBigToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapBigToHostInt32(mh->cputype) == CPU_TYPE_POWERPC)) {
+                               fRebasers.push_back(new Rebaser<ppc>(mh));
+                       }
+                       else if ( (OSSwapBigToHostInt32(mh->magic) == MH_MAGIC_64) && (OSSwapBigToHostInt32(mh->cputype) == CPU_TYPE_POWERPC64)) {
+                               fRebasers.push_back(new Rebaser<ppc64>(mh));
+                       }
+                       else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_I386)) {
+                               fRebasers.push_back(new Rebaser<x86>(mh));
+                       }
+                       else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC_64) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_X86_64)) {
+                               fRebasers.push_back(new Rebaser<x86_64>(mh));
+                       }
+                       else {
+                               throw "unknown file format";
+                       }
+               }
+               catch (const char* msg) {
+                       fprintf(stderr, "rebase warning: %s for %s\n", msg, path);
+               }
+       }
+       
+       fMappingAddress = p;
+       fFileSize = stat_buf.st_size;
+}
+
+
+MultiArchRebaser::~MultiArchRebaser()
+{
+       ::munmap(fMappingAddress, fFileSize);
+}
+
+void MultiArchRebaser::commit()
+{
+       ::msync(fMappingAddress, fFileSize, MS_ASYNC); 
+}
+
+
+
+template <typename A>
+Rebaser<A>::Rebaser(const void* machHeader)
+ :     fHeader((const macho_header<P>*)machHeader)
+{
+       switch ( fHeader->filetype() ) {
+               case MH_DYLIB:
+                       if ( (fHeader->flags() & MH_SPLIT_SEGS) != 0 )
+                               throw "split-seg dylibs cannot be rebased";
+                       break;
+               case MH_BUNDLE:
+                       break;
+               default:
+                       throw "file is not a dylib or bundle";
+       }
+               
+}
+
+template <> cpu_type_t Rebaser<ppc>::getArchitecture()    const { return CPU_TYPE_POWERPC; }
+template <> cpu_type_t Rebaser<ppc64>::getArchitecture()  const { return CPU_TYPE_POWERPC64; }
+template <> cpu_type_t Rebaser<x86>::getArchitecture()    const { return CPU_TYPE_I386; }
+template <> cpu_type_t Rebaser<x86_64>::getArchitecture() const { return CPU_TYPE_X86_64; }
+
+
+template <typename A>
+uint64_t Rebaser<A>::getBaseAddress() const
+{
+       uint64_t lowestSegmentAddress = LLONG_MAX;
+       const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
+       const uint32_t cmd_count = fHeader->ncmds();
+       const macho_load_command<P>* cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
+                       const macho_segment_command<P>* segCmd = (const macho_segment_command<P>*)cmd;
+                       if ( segCmd->vmaddr() < lowestSegmentAddress ) {
+                               lowestSegmentAddress = segCmd->vmaddr();
+                       }
+               }
+               cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+       }
+       return lowestSegmentAddress;
+}
+
+template <typename A>
+uint64_t Rebaser<A>::getVMSize() const
+{
+       const macho_segment_command<P>* highestSegmentCmd = NULL; 
+       const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
+       const uint32_t cmd_count = fHeader->ncmds();
+       const macho_load_command<P>* cmd = cmds;
+       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 ( (highestSegmentCmd == NULL) || (segCmd->vmaddr() > highestSegmentCmd->vmaddr()) ) {
+                               highestSegmentCmd = segCmd;
+                       }
+               }
+               cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+       }
+       
+       return ((highestSegmentCmd->vmaddr() + highestSegmentCmd->vmsize() - this->getBaseAddress() + 4095) & (-4096));
+}
+
+
+template <typename A>
+void Rebaser<A>::setBaseAddress(uint64_t addr)
+{
+       // calculate slide
+       fSlide = addr - this->getBaseAddress();
+       
+       // compute base address for relocations
+       this->setRelocBase();
+       
+       // build cache of section index to section 
+       this->buildSectionTable();
+               
+       // update load commands
+       this->adjustLoadCommands();
+       
+       // update symbol table  
+       this->adjustSymbolTable();
+       
+       // update writable segments that have internal pointers
+       this->adjustDATA();
+}
+
+template <typename A>
+void Rebaser<A>::adjustLoadCommands()
+{
+       const macho_segment_command<P>* highestSegmentCmd = NULL; 
+       const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
+       const uint32_t cmd_count = fHeader->ncmds();
+       const macho_load_command<P>* cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               switch ( cmd->cmd() ) {
+                       case LC_ID_DYLIB:
+                               if ( (fHeader->flags() & MH_PREBOUND) != 0 ) {
+                                       // clear timestamp so that any prebound clients are invalidated
+                                       macho_dylib_command<P>* dylib  = (macho_dylib_command<P>*)cmd;
+                                       dylib->set_timestamp(1);
+                               }
+                               break;
+                       case LC_LOAD_DYLIB:
+                       case LC_LOAD_WEAK_DYLIB:
+                               if ( (fHeader->flags() & MH_PREBOUND) != 0 ) {
+                                       // clear expected timestamps so that this image will load with invalid prebinding 
+                                       macho_dylib_command<P>* dylib  = (macho_dylib_command<P>*)cmd;
+                                       dylib->set_timestamp(2);
+                               }
+                               break;
+                       case macho_routines_command<P>::CMD:
+                               // update -init command
+                               {
+                                       struct macho_routines_command<P>* routines = (struct macho_routines_command<P>*)cmd;
+                                       routines->set_init_address(routines->init_address() + fSlide);
+                               }
+                               break;
+                       case macho_segment_command<P>::CMD:
+                               // update segment commands
+                               {
+                                       macho_segment_command<P>* seg = (macho_segment_command<P>*)cmd;
+                                       seg->set_vmaddr(seg->vmaddr() + fSlide);
+                                       macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)seg + sizeof(macho_segment_command<P>));
+                                       macho_section<P>* const sectionsEnd = &sectionsStart[seg->nsects()];
+                                       for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
+                                               sect->set_addr(sect->addr() + fSlide);
+                                       }
+                               }
+                               break;
+               }
+               cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+       }
+}
+
+
+template <typename A>
+void Rebaser<A>::buildSectionTable()
+{
+       // build vector of sections
+       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>* seg = (macho_segment_command<P>*)cmd;
+                       vmmap mapping;
+                       mapping.vmaddr = seg->vmaddr();
+                       mapping.vmsize = seg->vmsize();
+                       mapping.fileoff = seg->fileoff();
+                       fVMMApping.push_back(mapping);
+               }
+               cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+       }       
+}
+
+
+template <typename A>
+void Rebaser<A>::adjustSymbolTable()
+{
+       const macho_dysymtab_command<P>* dysymtab = NULL;
+       macho_nlist<P>* symbolTable = NULL;
+
+       // get symbol table info
+       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) {
+               switch (cmd->cmd()) {
+                       case LC_SYMTAB:
+                               {
+                                       const macho_symtab_command<P>* symtab = (macho_symtab_command<P>*)cmd;
+                                       symbolTable = (macho_nlist<P>*)(((uint8_t*)fHeader) + symtab->symoff());
+                               }
+                               break;
+                       case LC_DYSYMTAB:
+                               dysymtab = (macho_dysymtab_command<P>*)cmd;
+                               break;
+               }
+               cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+       }       
+
+       // walk all exports and slide their n_value
+       macho_nlist<P>* lastExport = &symbolTable[dysymtab->iextdefsym()+dysymtab->nextdefsym()];
+       for (macho_nlist<P>* entry = &symbolTable[dysymtab->iextdefsym()]; entry < lastExport; ++entry) {
+               if ( (entry->n_type() & N_TYPE) == N_SECT )
+                       entry->set_n_value(entry->n_value() + fSlide);
+       }
+
+       // walk all local symbols and slide their n_value
+       macho_nlist<P>* lastLocal = &symbolTable[dysymtab->ilocalsym()+dysymtab->nlocalsym()];
+       for (macho_nlist<P>* entry = &symbolTable[dysymtab->ilocalsym()]; entry < lastLocal; ++entry) {
+               if ( entry->n_sect() != NO_SECT )
+                       entry->set_n_value(entry->n_value() + fSlide);
+       }
+}
+
+template <typename A>
+void Rebaser<A>::adjustDATA()
+{
+       const macho_dysymtab_command<P>* dysymtab = NULL;
+
+       // get symbol table info
+       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) {
+               switch (cmd->cmd()) {
+                       case LC_DYSYMTAB:
+                               dysymtab = (macho_dysymtab_command<P>*)cmd;
+                               break;
+               }
+               cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+       }       
+
+       // walk all local relocations and slide every pointer
+       const macho_relocation_info<P>* const relocsStart = (macho_relocation_info<P>*)(((uint8_t*)fHeader) + dysymtab->locreloff());
+       const macho_relocation_info<P>* const relocsEnd = &relocsStart[dysymtab->nlocrel()];
+       for (const macho_relocation_info<P>* reloc=relocsStart; reloc < relocsEnd; ++reloc) {
+               this->doLocalRelocation(reloc);
+       }
+       
+       // walk non-lazy-pointers and slide the ones that are LOCAL
+       cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
+                       const macho_segment_command<P>* seg = (macho_segment_command<P>*)cmd;
+                       const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)seg + sizeof(macho_segment_command<P>));
+                       const macho_section<P>* const sectionsEnd = &sectionsStart[seg->nsects()];
+                       const uint32_t* const indirectTable = (uint32_t*)(((uint8_t*)fHeader) + dysymtab->indirectsymoff());
+                       for(const macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
+                               if ( (sect->flags() & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS ) {
+                                       const uint32_t indirectTableOffset = sect->reserved1();
+                                       uint32_t pointerCount = sect->size() / sizeof(pint_t);
+                                       pint_t* nonLazyPointer = (pint_t*)(((uint8_t*)fHeader) + sect->offset());
+                                       for (uint32_t i=0; i < pointerCount; ++i, ++nonLazyPointer) {
+                                               if ( E::get32(indirectTable[indirectTableOffset + i]) == INDIRECT_SYMBOL_LOCAL ) {
+                                                       P::setP(*nonLazyPointer, A::P::getP(*nonLazyPointer) + fSlide);
+                                               }
+                                       }
+                               }
+                       }
+               }
+               cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+       }       
+       
+}
+
+
+template <typename A>
+typename A::P::uint_t* Rebaser<A>::mappedAddressForVMAddress(uint32_t vmaddress)
+{
+       for(typename std::vector<vmmap>::iterator it = fVMMApping.begin(); it != fVMMApping.end(); ++it) {
+               //fprintf(stderr, "vmaddr=0x%08lX, vmsize=0x%08lX\n", it->vmaddr, it->vmsize);
+               if ( (vmaddress >= it->vmaddr) && (vmaddress < (it->vmaddr+it->vmsize)) ) {
+                       return (pint_t*)((vmaddress - it->vmaddr) + it->fileoff + (uint8_t*)fHeader);
+               }
+       }
+       throwf("reloc address 0x%08X not found", vmaddress);
+}
+
+
+template <>
+void Rebaser<x86_64>::doLocalRelocation(const macho_relocation_info<x86_64::P>* reloc)
+{
+       if ( reloc->r_type() == X86_64_RELOC_UNSIGNED ) {
+               pint_t* addr = mappedAddressForVMAddress(reloc->r_address() + fOrignalVMRelocBaseAddress);
+               P::setP(*addr, P::getP(*addr) + fSlide);
+       }
+       else {
+               throw "invalid relocation type";
+       }
+}
+
+template <>
+void Rebaser<ppc>::doLocalRelocation(const macho_relocation_info<P>* reloc)
+{
+       if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
+               if ( reloc->r_type() == GENERIC_RELOC_VANILLA ) {
+                       pint_t* addr = mappedAddressForVMAddress(reloc->r_address() + fOrignalVMRelocBaseAddress);
+                       P::setP(*addr, P::getP(*addr) + fSlide);
+               }
+       }
+       else {
+               macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
+               if ( sreloc->r_type() == PPC_RELOC_PB_LA_PTR ) {
+                       sreloc->set_r_value( sreloc->r_value() + fSlide );
+               }
+               else {
+                       throw "cannot rebase final linked image with scattered relocations";
+               }
+       }
+}
+
+template <>
+void Rebaser<x86>::doLocalRelocation(const macho_relocation_info<P>* reloc)
+{
+       if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
+               if ( reloc->r_type() == GENERIC_RELOC_VANILLA ) {
+                       pint_t* addr = mappedAddressForVMAddress(reloc->r_address() + fOrignalVMRelocBaseAddress);
+                       P::setP(*addr, P::getP(*addr) + fSlide);
+               }
+       }
+       else {
+               macho_scattered_relocation_info<P>* sreloc = (macho_scattered_relocation_info<P>*)reloc;
+               if ( sreloc->r_type() == GENERIC_RELOC_PB_LA_PTR ) {
+                       sreloc->set_r_value( sreloc->r_value() + fSlide );
+               }
+               else {
+                       throw "cannot rebase final linked image with scattered relocations";
+               }
+       }
+}
+
+template <typename A>
+void Rebaser<A>::doLocalRelocation(const macho_relocation_info<P>* reloc)
+{
+       if ( (reloc->r_address() & R_SCATTERED) == 0 ) {
+               if ( reloc->r_type() == GENERIC_RELOC_VANILLA ) {
+                       pint_t* addr = mappedAddressForVMAddress(reloc->r_address() + fOrignalVMRelocBaseAddress);
+                       P::setP(*addr, P::getP(*addr) + fSlide);
+               }
+       }
+       else {
+               throw "cannot rebase final linked image with scattered relocations";
+       }
+}
+
+
+template <typename A>
+void Rebaser<A>::setRelocBase()
+{
+       // reloc addresses are from the start of the mapped file (base address)
+       fRelocBase = (pint_t)fHeader;
+       fOrignalVMRelocBaseAddress = this->getBaseAddress();
+       //fprintf(stderr, "fOrignalVMRelocBaseAddress=0x%08X\n", fOrignalVMRelocBaseAddress);
+}
+
+template <>
+void Rebaser<ppc64>::setRelocBase()
+{
+       // reloc addresses either:
+       // 1) from the base address if no writable segment is > 4GB from base address
+       // 2) from start of first writable segment
+       const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
+       const uint32_t cmd_count = fHeader->ncmds();
+       const macho_load_command<P>* cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
+                       const macho_segment_command<P>* segCmd = (const macho_segment_command<P>*)cmd;
+                       if ( segCmd->initprot() & VM_PROT_WRITE ) {
+                               if ( (segCmd->vmaddr() + segCmd->vmsize() - this->getBaseAddress()) > 0x100000000ULL ) {
+                                       // found writable segment with address > 4GB past base address
+                                       fRelocBase = segCmd->fileoff() + (pint_t)fHeader;
+                                       fOrignalVMRelocBaseAddress = segCmd->vmaddr();
+                                       return;
+                               }
+                       }
+               }
+               cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+       }
+       // just use base address
+       fRelocBase = (pint_t)fHeader;
+       fOrignalVMRelocBaseAddress = this->getBaseAddress();
+}
+
+template <>
+void Rebaser<x86_64>::setRelocBase()
+{
+       // reloc addresses are always based from the start of the first writable segment
+       const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
+       const uint32_t cmd_count = fHeader->ncmds();
+       const macho_load_command<P>* cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
+                       const macho_segment_command<P>* segCmd = (const macho_segment_command<P>*)cmd;
+                       if ( segCmd->initprot() & VM_PROT_WRITE ) {
+                               fRelocBase = segCmd->fileoff() + (pint_t)fHeader;
+                               fOrignalVMRelocBaseAddress = segCmd->vmaddr();
+                               return;
+                       }
+               }
+               cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+       }
+       throw "no writable segment";
+}
+
+
+static void copyFile(const char* srcFile, const char* dstFile)
+{
+       // open files 
+       int src = open(srcFile, O_RDONLY);      
+       if ( src == -1 )
+               throwf("can't open file %s, errno=%d", srcFile, errno);
+       struct stat stat_buf;
+       if ( fstat(src, &stat_buf) == -1)
+               throwf("can't stat open file %s, errno=%d", srcFile, errno);
+               
+       // create new file with all same permissions to hold copy of dylib 
+       ::unlink(dstFile);
+       int dst = open(dstFile, O_CREAT | O_RDWR | O_TRUNC, stat_buf.st_mode);  
+       if ( dst == -1 )
+               throwf("can't create temp file %s, errnor=%d", dstFile, errno);
+
+       // mark source as "don't cache"
+       (void)fcntl(src, F_NOCACHE, 1);
+       // we want to cache the dst because we are about to map it in and modify it
+       
+       // copy permission bits
+       if ( chmod(dstFile, stat_buf.st_mode & 07777) == -1 )
+               throwf("can't chmod temp file %s, errno=%d", dstFile, errno);
+       if ( chown(dstFile, stat_buf.st_uid, stat_buf.st_gid) == -1)
+               throwf("can't chown temp file %s, errno=%d", dstFile, errno);
+                 
+       // copy contents
+       ssize_t len;
+       const uint32_t kBufferSize = 128*1024;
+       static uint8_t* buffer = NULL;
+       if ( buffer == NULL ) {
+               vm_address_t addr = 0;
+               if ( vm_allocate(mach_task_self(), &addr, kBufferSize, true /*find range*/) == KERN_SUCCESS )
+                       buffer = (uint8_t*)addr;
+               else
+                       throw "can't allcoate copy buffer";
+       }
+       while ( (len = read(src, buffer, kBufferSize)) > 0 ) {
+               if ( write(dst, buffer, len) == -1 )
+                       throwf("write failure copying feil %s, errno=%d", dstFile, errno);
+       }
+               
+       // close files 
+       int result1 = close(dst);
+       int result2 = close(src);
+       if ( (result1 != 0) || (result2 != 0) )
+               throw "can't close file";
+}
+
+
+// scan dylibs and collect size info
+// calculate new base address for each dylib
+// rebase each file
+//             copy to temp and mmap
+//             update content
+//             unmap/flush
+//             rename
+
+struct archInfo {
+       cpu_type_t      arch;
+       uint64_t        vmSize;
+       uint64_t        orgBase;
+       uint64_t        newBase;
+};
+
+struct fileInfo
+{
+       fileInfo(const char* p) : path(p) {}
+       
+       const char*                             path;
+       std::vector<archInfo>   archs;
+};
+
+//
+// add archInfos to fileInfo for every slice of a fat file
+// for ppc, there may be duplicate architectures (with different sub-types)
+//
+static void setSizes(fileInfo& info, const std::set<cpu_type_t>& onlyArchs)
+{
+       const MultiArchRebaser mar(info.path);
+       const std::vector<AbstractRebaser*>&    rebasers = mar.getArchs();
+       for(std::set<cpu_type_t>::iterator ait=onlyArchs.begin(); ait != onlyArchs.end(); ++ait) {
+               for(std::vector<AbstractRebaser*>::const_iterator rit=rebasers.begin(); rit != rebasers.end(); ++rit) {
+                       AbstractRebaser* rebaser = *rit;
+                       if ( rebaser->getArchitecture() == *ait ) {
+                               archInfo ai;
+                               ai.arch = *ait;
+                               ai.vmSize = rebaser->getVMSize();
+                               ai.orgBase = rebaser->getBaseAddress();
+                               ai.newBase = 0;
+                               //fprintf(stderr, "base=0x%llX, size=0x%llX\n", ai.orgBase, ai.vmSize);
+                               info.archs.push_back(ai);
+                       }
+               }
+       }
+}
+
+static const char* nameForArch(cpu_type_t arch)
+{
+       switch( arch ) {
+               case CPU_TYPE_POWERPC:
+                       return "ppc";
+               case CPU_TYPE_POWERPC64:
+                       return "ppca64";
+               case CPU_TYPE_I386:
+                       return "i386";
+               case CPU_TYPE_X86_64:
+                       return "x86_64";
+       }
+       return "unknown";
+}
+
+static void rebase(const fileInfo& info)
+{
+       // generate temp file name
+       char realFilePath[PATH_MAX];
+       if ( realpath(info.path, realFilePath) == NULL ) {
+               throwf("realpath() failed on %s, errno=%d", info.path, errno);
+       }
+       const char* tempPath;
+       asprintf((char**)&tempPath, "%s_rebase", realFilePath);
+
+       // copy whole file to temp file 
+       copyFile(info.path, tempPath);
+       
+       try {
+               // rebase temp file
+               MultiArchRebaser mar(tempPath, true);
+               const std::vector<AbstractRebaser*>&    rebasers = mar.getArchs();
+               for(std::vector<archInfo>::const_iterator fait=info.archs.begin(); fait != info.archs.end(); ++fait) {
+                       for(std::vector<AbstractRebaser*>::const_iterator rit=rebasers.begin(); rit != rebasers.end(); ++rit) {
+                               if ( (*rit)->getArchitecture() == fait->arch ) {
+                                       (*rit)->setBaseAddress(fait->newBase);
+                                       if ( verbose )
+                                               printf("%8s 0x%0llX -> 0x%0llX  %s\n", nameForArch(fait->arch), fait->orgBase, fait->newBase, info.path);
+                               }
+                       }       
+               }
+               
+               // flush temp file out to disk
+               mar.commit();
+               
+               // rename
+               int result = rename(tempPath, info.path);
+               if ( result != 0 ) {
+                       throwf("can't swap temporary rebased file: rename(%s,%s) returned errno=%d", tempPath, info.path, errno);
+               }
+               
+               // make sure every really gets out to disk
+               ::sync();
+       }
+       catch (const char* msg) {
+               // delete temp file
+               ::unlink(tempPath);
+               
+               // throw exception with file name added
+               const char* newMsg;
+               asprintf((char**)&newMsg, "%s for file %s", msg, info.path);
+               throw newMsg;
+       }
+}
+
+static uint64_t totalVMSize(cpu_type_t arch, std::vector<fileInfo>& files)
+{
+       uint64_t totalSize = 0;
+       for(std::vector<fileInfo>::iterator fit=files.begin(); fit != files.end(); ++fit) {
+               fileInfo& fi = *fit;
+               for(std::vector<archInfo>::iterator fait=fi.archs.begin(); fait != fi.archs.end(); ++fait) {
+                       if ( fait->arch == arch )
+                               totalSize += fait->vmSize;
+               }
+       }       
+       return totalSize;
+}
+
+static uint64_t startAddress(cpu_type_t arch, std::vector<fileInfo>& files, uint64_t lowAddress, uint64_t highAddress)
+{
+       if ( lowAddress != 0 ) 
+               return lowAddress;
+       else if ( highAddress != 0 ) {
+               uint64_t totalSize = totalVMSize(arch, files);
+               if ( highAddress < totalSize )
+                       throwf("cannot use -high_address 0x%X because total size of images is greater: 0x%X", highAddress, totalSize);
+               return highAddress - totalSize;
+       }
+       else {
+               if ( (arch == CPU_TYPE_I386) || (arch == CPU_TYPE_POWERPC) ) {
+                       // place dylibs below dyld
+                       uint64_t topAddr = 0x8FE00000;
+                       uint64_t totalSize = totalVMSize(arch, files);
+                       if ( totalSize > topAddr )
+                               throwf("total size of images (0x%X) does not fit below 0x8FE00000", totalSize);
+                       return topAddr - totalSize;
+               }
+               else if ( arch == CPU_TYPE_POWERPC64 ) {
+                       return 0x200000000ULL;
+               }
+               else if ( arch == CPU_TYPE_X86_64 ) {
+                       return 0x200000000ULL;
+               }
+               else
+                       throw "unknown architecture";
+       }
+}
+
+static void usage()
+{
+       fprintf(stderr, "rebase [-low_address] [-high_address] [-v] [-arch <arch>] files...\n");
+}
+
+
+int main(int argc, const char* argv[])
+{
+       std::vector<fileInfo> files;
+       std::set<cpu_type_t> onlyArchs;
+       uint64_t lowAddress = 0;
+       uint64_t highAddress = 0;
+
+       try {
+               // parse command line options
+               char* endptr;
+               for(int i=1; i < argc; ++i) {
+                       const char* arg = argv[i];
+                       if ( arg[0] == '-' ) {
+                               if ( strcmp(arg, "-v") == 0 ) {
+                                       verbose = true;
+                               }
+                               else if ( strcmp(arg, "-low_address") == 0 ) {
+                                       lowAddress = strtoull(argv[++i], &endptr, 16);
+                               }
+                               else if ( strcmp(arg, "-high_address") == 0 ) {
+                                       highAddress = strtoull(argv[++i], &endptr, 16);
+                               }
+                               else if ( strcmp(arg, "-arch") == 0 ) {
+                                       const char* arch = argv[++i];
+                                       if ( strcmp(arch, "ppc") == 0 ) 
+                                               onlyArchs.insert(CPU_TYPE_POWERPC);
+                                       else if ( strcmp(arch, "ppc64") == 0 )
+                                               onlyArchs.insert(CPU_TYPE_POWERPC64);
+                                       else if ( strcmp(arch, "i386") == 0 )
+                                               onlyArchs.insert(CPU_TYPE_I386);
+                                       else if ( strcmp(arch, "x86_64") == 0 )
+                                               onlyArchs.insert(CPU_TYPE_X86_64);
+                                       else 
+                                               throwf("unknown architecture %s", arch);
+                               }
+                               else {
+                                       usage();
+                                       throwf("unknown option: %s\n", arg);
+                               }
+                       }
+                       else {
+                               files.push_back(fileInfo(arg));
+                       }
+               }
+               
+               if ( files.size() == 0 )
+                       throw "no files specified";
+               
+               // use all architectures if no restrictions specified
+               if ( onlyArchs.size() == 0 ) {
+                       onlyArchs.insert(CPU_TYPE_POWERPC);
+                       onlyArchs.insert(CPU_TYPE_POWERPC64);
+                       onlyArchs.insert(CPU_TYPE_I386);
+                       onlyArchs.insert(CPU_TYPE_X86_64);
+               }
+               
+               // scan files and collect sizes
+               for(std::vector<fileInfo>::iterator it=files.begin(); it != files.end(); ++it) {
+                       setSizes(*it, onlyArchs);
+               }
+                               
+               // assign new base address for each arch
+               for(std::set<cpu_type_t>::iterator ait=onlyArchs.begin(); ait != onlyArchs.end(); ++ait) {
+                       cpu_type_t arch = *ait;
+                       uint64_t baseAddress = startAddress(arch, files, lowAddress, highAddress);
+                       for(std::vector<fileInfo>::iterator fit=files.begin(); fit != files.end(); ++fit) {
+                               fileInfo& fi = *fit;
+                               for(std::vector<archInfo>::iterator fait=fi.archs.begin(); fait != fi.archs.end(); ++fait) {
+                                       if ( fait->arch == arch ) {
+                                               fait->newBase = baseAddress;
+                                               baseAddress += fait->vmSize; 
+                                               baseAddress = (baseAddress + 4095) & (-4096);  // page align
+                                       }
+                               }
+                       }
+               }
+               
+               // rebase each file if it contains something rebaseable
+               for(std::vector<fileInfo>::iterator it=files.begin(); it != files.end(); ++it) {
+                       fileInfo& fi = *it;
+                       if ( fi.archs.size() > 0 )
+                               rebase(fi);
+               }
+               
+       }
+       catch (const char* msg) {
+               fprintf(stderr, "rebase failed: %s\n", msg);
+               return 1;
+       }
+       
+       return 0;
+}
+
+
+
index 7d41e765012c900c21ac0785f501871cf7ac4676..266eb8502a3627bc256ea429356be82b12eeadff 100644 (file)
@@ -21,14 +21,17 @@ OTOOL = otool
 ifeq (${ARCH},ppc64)
 OTOOL = otool64
 endif
+ifeq (${ARCH},x86_64)
+OTOOL = otool64
+endif
 
 
 CC              = gcc-4.0 -arch ${ARCH}
-CCFLAGS = -Wall -g -std=c99
+CCFLAGS = -Wall -std=c99
 ASMFLAGS =
 
 CXX              = g++-4.0 -arch ${ARCH}
-CXXFLAGS = -Wall -g
+CXXFLAGS = -Wall
 
 RM      = rm
 RMFLAGS = -rf
index a18560a475bcba86d212adf040dba653c6b107bf..3756bd156c928d4d189b248d66b6941e7057f20d 100755 (executable)
@@ -3,7 +3,7 @@
 # cd into test-cases directory
 cd `echo "$0" | sed 's/run-all-unit-tests/test-cases/'`
 
-all_archs="ppc ppc64 i386"
+all_archs="ppc ppc64 i386 x86_64"
 
 for arch in $all_archs
 do
diff --git a/unit-tests/test-cases/bundle_loader/Makefile b/unit-tests/test-cases/bundle_loader/Makefile
new file mode 100644 (file)
index 0000000..3b31968
--- /dev/null
@@ -0,0 +1,43 @@
+##
+# 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
+# -bundle_loader works, and _bar is found in the executable
+# and not in libbar.dylib
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} bar.c -dynamiclib -o libbar.dylib
+       ${CC} ${CCFLAGS} main.c bar.c -o main
+       ${CC} ${CCFLAGS} bundle.c -bundle -bundle_loader main libbar.dylib -o bundle.bundle
+       ${FAIL_IF_BAD_MACHO} bundle.bundle
+       nm -m bundle.bundle | grep _bar | grep "from executable" | ${PASS_IFF_STDIN}
+
+clean:
+       rm libbar.dylib main bundle.bundle
+       
+
diff --git a/unit-tests/test-cases/bundle_loader/bar.c b/unit-tests/test-cases/bundle_loader/bar.c
new file mode 100644 (file)
index 0000000..b737953
--- /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@
+ */
+
+
+// funcation called by a loaded bundle
+int bar() 
+{
+       return 1;
+}
+
diff --git a/unit-tests/test-cases/bundle_loader/bundle.c b/unit-tests/test-cases/bundle_loader/bundle.c
new file mode 100644 (file)
index 0000000..ba78c28
--- /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 bar();
+
+int foo()
+{
+       return bar();
+}
diff --git a/unit-tests/test-cases/bundle_loader/main.c b/unit-tests/test-cases/bundle_loader/main.c
new file mode 100644 (file)
index 0000000..c9e53f9
--- /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@
+ */
+#include <stdio.h>
+
+int main()
+{
+       return 0;
+}
+
diff --git a/unit-tests/test-cases/dead_strip/Makefile b/unit-tests/test-cases/dead_strip/Makefile
new file mode 100644 (file)
index 0000000..5985e96
--- /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 -dead_strip
+#
+# 1) in a main executable, dead globals are removed
+# 2) in a dylib/bundle with -exported_symbols_list, dead globals are removed
+# 3) in a dylib/bundle without -exported_symbols_list, dead globals are *not* removed
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} main.c deadwood.c -dead_strip -o main-${ARCH}
+       ${FAIL_IF_BAD_MACHO} main-${ARCH}
+       nm -j main-${ARCH} | egrep 'dead_wood|dead_door' | ${FAIL_IF_STDIN}
+       ${CC} ${CCFLAGS} -dynamiclib main.c deadwood.c -dead_strip -exported_symbols_list main.exp -o dylib-${ARCH}
+       ${FAIL_IF_BAD_MACHO} dylib-${ARCH}
+       nm -j dylib-${ARCH} | grep dead | ${FAIL_IF_STDIN}
+       ${CC} ${CCFLAGS} -dynamiclib main.c deadwood.c -dead_strip -o dylib2-${ARCH}
+       ${FAIL_IF_BAD_MACHO} dylib2-${ARCH}
+       nm -j dylib2-${ARCH} | grep dead_door_knob | ${FAIL_IF_EMPTY}
+       nm -j dylib2-${ARCH} | grep deadwood | ${PASS_IFF_EMPTY}
+       
+
+clean:
+       rm -rf main-${ARCH} dylib-${ARCH} dylib2-${ARCH}
+       
+
diff --git a/unit-tests/test-cases/dead_strip/deadwood.c b/unit-tests/test-cases/dead_strip/deadwood.c
new file mode 100644 (file)
index 0000000..176ec78
--- /dev/null
@@ -0,0 +1,11 @@
+
+
+// deadwood() is local to its linkage unit and is unsed,
+// so reference to undef() is ok
+
+extern void undef();
+
+void dead_wood() __attribute__((visibility("hidden")));
+void dead_wood() { undef(); }
+
+
diff --git a/unit-tests/test-cases/dead_strip/main.c b/unit-tests/test-cases/dead_strip/main.c
new file mode 100644 (file)
index 0000000..029aed9
--- /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@
+ */
+
+int main()
+{
+       return 0;
+}
+
+
+
+void dead_door_knob() {  }
diff --git a/unit-tests/test-cases/dead_strip/main.exp b/unit-tests/test-cases/dead_strip/main.exp
new file mode 100644 (file)
index 0000000..4eb9e89
--- /dev/null
@@ -0,0 +1 @@
+_main
diff --git a/unit-tests/test-cases/dwarf-debug-notes-r/Makefile b/unit-tests/test-cases/dwarf-debug-notes-r/Makefile
new file mode 100644 (file)
index 0000000..b7f4eeb
--- /dev/null
@@ -0,0 +1,61 @@
+##
+# 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 after
+# some of the .o files are merged with ld -r.
+# 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: foobar.o main.o crt1.o 
+       ${CXX} ${CCXXFLAGS} foobar.o main.o -o dwarf-test-${ARCH} -L.
+       ${FAIL_IF_BAD_MACHO} dwarf-test-${ARCH}
+       nm -ap dwarf-test-${ARCH} | ./stabs-filter.pl > dwarf-test-${ARCH}.stabs
+       ${PASS_IFF} diff dwarf-test-${ARCH}.stabs expected-stabs
+
+foobar.o : foo.o bar.o
+       ${LD} -r foo.o bar.o -o foobar.o
+       
+foo.o : foo.cxx
+       ${CXX} ${CCXXFLAGS} -gdwarf-2 foo.cxx -c -o foo.o -mdynamic-no-pic
+
+bar.o : bar.cxx
+       ${CXX} ${CCXXFLAGS} -gdwarf-2 bar.cxx -c -o bar.o -mdynamic-no-pic
+
+main.o : main.cxx
+       ${CXX} ${CCXXFLAGS} -gdwarf-2 main.cxx -c -o main.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-test-${ARCH}  foo.o bar.o foobar.o main.o crt1.o dwarf-test-${ARCH}.stabs
+
+
diff --git a/unit-tests/test-cases/dwarf-debug-notes-r/bar.cxx b/unit-tests/test-cases/dwarf-debug-notes-r/bar.cxx
new file mode 100644 (file)
index 0000000..c3f6a18
--- /dev/null
@@ -0,0 +1,4 @@
+int bar()
+{
+  return 10;
+}
diff --git a/unit-tests/test-cases/dwarf-debug-notes-r/expected-stabs b/unit-tests/test-cases/dwarf-debug-notes-r/expected-stabs
new file mode 100644 (file)
index 0000000..4853628
--- /dev/null
@@ -0,0 +1,24 @@
+0000    SO CWD/
+0000    SO foo.cxx
+0001   OSO CWD/foo.o
+0000 BNSYM 
+0000   FUN __Z3foov
+0000   FUN 
+0000 ENSYM 
+0000    SO 
+0000    SO CWD/
+0000    SO bar.cxx
+0001   OSO CWD/bar.o
+0000 BNSYM 
+0000   FUN __Z3barv
+0000   FUN 
+0000 ENSYM 
+0000    SO 
+0000    SO CWD/
+0000    SO main.cxx
+0001   OSO CWD/main.o
+0000 BNSYM 
+0000   FUN _main
+0000   FUN 
+0000 ENSYM 
+0000    SO 
diff --git a/unit-tests/test-cases/dwarf-debug-notes-r/foo.cxx b/unit-tests/test-cases/dwarf-debug-notes-r/foo.cxx
new file mode 100644 (file)
index 0000000..1f46ef4
--- /dev/null
@@ -0,0 +1,4 @@
+int foo()
+{
+  return 10;
+}
diff --git a/unit-tests/test-cases/dwarf-debug-notes-r/main.cxx b/unit-tests/test-cases/dwarf-debug-notes-r/main.cxx
new file mode 100644 (file)
index 0000000..f8b643a
--- /dev/null
@@ -0,0 +1,4 @@
+int main()
+{
+  return 0;
+}
diff --git a/unit-tests/test-cases/dwarf-debug-notes-r/stabs-filter.pl b/unit-tests/test-cases/dwarf-debug-notes-r/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";
+       }
+}
+
+
index 756776ee996b6d68b564033dacfbc027b28815a9..38f4c8c72d301fbd3849759d577a1add8e854f6c 100644 (file)
@@ -1,4 +1,4 @@
-0000    SO CWD
+0000    SO CWD/
 0000    SO hello.cxx
 0001   OSO CWD/hello.o
 0000 BNSYM 
@@ -11,7 +11,7 @@
 0000   FUN 
 0000 ENSYM 
 0000    SO 
-0000    SO CWD
+0000    SO CWD/
 0000    SO other.cxx
 0001   OSO CWD/other.o
 0000 BNSYM 
diff --git a/unit-tests/test-cases/filelist/Makefile b/unit-tests/test-cases/filelist/Makefile
new file mode 100644 (file)
index 0000000..78a1004
--- /dev/null
@@ -0,0 +1,48 @@
+##
+# 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
+
+
+PWD = $(shell pwd)
+
+#
+# The point of this test is to check the two forms of the'
+#  -filelist option
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} -c hello.c -o hello-${ARCH}.o
+       echo "${PWD}/hello-${ARCH}.o" > "${PWD}/filelist1"
+       cd /tmp && ${CC} ${CCFLAGS} -arch ${ARCH} -filelist "${PWD}/filelist1"  -o "${PWD}/hello-${ARCH}"
+       ${FAIL_IF_BAD_MACHO} hello-${ARCH}
+       echo "hello-${ARCH}.o" > "${PWD}/filelist2"
+       cd /tmp && ${CC} ${CCFLAGS}  -arch ${ARCH} -filelist "${PWD}/filelist2,${PWD}" -o "${PWD}/hello-${ARCH}"
+       ${PASS_IFF_GOOD_MACHO} hello-${ARCH}
+
+clean:
+       rm  hello-${ARCH} hello-${ARCH}.o filelist1 filelist2
+       
+
diff --git a/unit-tests/test-cases/filelist/hello.c b/unit-tests/test-cases/filelist/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/late-link-error/Makefile b/unit-tests/test-cases/late-link-error/Makefile
new file mode 100644 (file)
index 0000000..209d5a3
--- /dev/null
@@ -0,0 +1,43 @@
+##
+# 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 sanity check that if
+# ld errors out during linking, that no output file is remaining
+#
+
+run: all
+
+all:
+       ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} link_error.s -dynamiclib -o link_error-${ARCH}  2> fail.log
+       ${FAIL_IFF} cat link_error-${ARCH}  2> fail.log
+
+clean:
+       rm link_error-${ARCH} fail.log
+       
+
diff --git a/unit-tests/test-cases/late-link-error/link_error.s b/unit-tests/test-cases/late-link-error/link_error.s
new file mode 100644 (file)
index 0000000..65de2ef
--- /dev/null
@@ -0,0 +1,18 @@
+
+
+#if __ppc__ || __ppc64__
+       ; illegal absolute load
+_foo:  lis r2,ha16(_strcmp)
+#endif
+
+#if __i386__
+       // illegal absolute load
+_foo:  movl  _strcmp, %eax
+#endif
+
+
+#if __x86_64__
+       // illegal external load
+_foo:  movl  _strcmp(%rip), %eax
+#endif
+
index dc3b340abdf5a7bdb7b4146cf3e04b8f35928484..45598933926dcb25d597e12696d243c7d3fb1f35 100644 (file)
@@ -35,10 +35,12 @@ _foo3:
                
                
                
+       .align 2
 _bar:
                nop
                
                
+       .align 2
        .globl _xx
        .globl __xx
 _xx:
@@ -46,6 +48,7 @@ __xx:
                nop
                
                
+       .align 2
 _ok:
                nop
                
diff --git a/unit-tests/test-cases/objc-references/Makefile b/unit-tests/test-cases/objc-references/Makefile
new file mode 100644 (file)
index 0000000..169963b
--- /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@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+
+#
+# The point of this test is to verify an Objective-C object file
+# is parsed to find the proper class references
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} test.m -c -o test.${ARCH}.o
+       ${LD} -arch ${ARCH} -r test.${ARCH}.o -o test-r.${ARCH}.o
+       nm test-r.${ARCH}.o | grep '.objc_class_name_NSObject' | ${FAIL_IF_EMPTY} 
+       nm test-r.${ARCH}.o | grep '.objc_class_name_NSData'   | ${FAIL_IF_EMPTY} 
+       nm test-r.${ARCH}.o | grep '.objc_class_name_NSArray'  | ${FAIL_IF_EMPTY} 
+       nm test-r.${ARCH}.o | grep '.objc_class_name_NSString' | ${PASS_IFF_STDIN} 
+
+clean:
+       rm -rf test.${ARCH}.o test.${ARCH}.o.dump
+               
+
+       #${OBJECTDUMP} -no_content test.${ARCH}.o > test.${ARCH}.o.dump
+       #grep '.objc_class_name_NSObject' test.${ARCH}.o.dump | ${FAIL_IF_EMPTY} 
+       #grep '.objc_class_name_NSString' test.${ARCH}.o.dump | ${PASS_IFF_STDIN} 
diff --git a/unit-tests/test-cases/objc-references/test.m b/unit-tests/test-cases/objc-references/test.m
new file mode 100644 (file)
index 0000000..d845227
--- /dev/null
@@ -0,0 +1,52 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <Foundation/Foundation.h>
+
+
+@interface Foo : NSObject
+- (NSString*) foo;
+@end
+
+
+@implementation Foo
+- (NSString*) foo
+{
+       return [NSString stringWithUTF8String:"hello"];
+}
+@end
+
+
+@interface Bar : NSData
+- (NSArray*) bar;
+@end
+
+
+@implementation Bar
+- (NSArray*) bar
+{
+       return [NSArray array];
+}
+@end
+
diff --git a/unit-tests/test-cases/rebase-basic/Makefile b/unit-tests/test-cases/rebase-basic/Makefile
new file mode 100644 (file)
index 0000000..2077033
--- /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 to see that a dylib 
+# run through the rebase tool is the same as if
+# the dylib was originally built at that address
+#
+
+run: all
+
+all:
+       ${CC} -arch ${ARCH} -c foo.c -o foo.${ARCH}.o
+       ${CC} -arch ${ARCH} -c bar.m -o bar.${ARCH}.o
+       ${CC} -arch ${ARCH} foo.${ARCH}.o bar.${ARCH}.o -dynamiclib -o libfoo.${ARCH}.dylib -framework Foundation -single_module -mmacosx-version-min=10.5
+       ${CC} -arch ${ARCH} foo.${ARCH}.o bar.${ARCH}.o -dynamiclib -o libfoo-alt.${ARCH}.dylib -framework Foundation -single_module -mmacosx-version-min=10.5 -seg1addr 0x12340000 -install_name libfoo.${ARCH}.dylib
+       rebase -arch ${ARCH} -low_address 0x12340000 libfoo.${ARCH}.dylib
+       ${FAIL_IF_BAD_MACHO} libfoo.${ARCH}.dylib
+       ${PASS_IFF} diff libfoo.${ARCH}.dylib libfoo-alt.${ARCH}.dylib
+
+clean:
+       rm foo.${ARCH}.o bar.${ARCH}.o libfoo.${ARCH}.dylib libfoo-alt.${ARCH}.dylib
+       
+
diff --git a/unit-tests/test-cases/rebase-basic/bar.m b/unit-tests/test-cases/rebase-basic/bar.m
new file mode 100644 (file)
index 0000000..ff4f2ac
--- /dev/null
@@ -0,0 +1,13 @@
+#include <Foundation/Foundation.h>
+
+@interface Bar : NSObject
+
+-(void) blah;
+
+@end
+
+@implementation Bar
+
+-(void) blah {}
+
+@end
\ No newline at end of file
diff --git a/unit-tests/test-cases/rebase-basic/foo.c b/unit-tests/test-cases/rebase-basic/foo.c
new file mode 100644 (file)
index 0000000..15d4ae6
--- /dev/null
@@ -0,0 +1,14 @@
+
+int foo() { return 10; }
+
+void* foop = &foo;
+
+int glob = 5;
+
+int* globp = &glob;
+
+
+int big[3000];
+
+
\ No newline at end of file
index 5a40e49464b746ce7e28980d9e8d73d80fe5dd3e..0629125241deb65c3a9ca02664399cc9dc415188 100644 (file)
@@ -190,6 +190,77 @@ _test_branches:
 
 
 
+#if __x86_64__
+       .text
+       .align 2
+       
+       .globl _test_loads
+_test_loads:
+
+       # PIC load of a 
+       movl    _a(%rip), %eax
+       
+       # PIC load of a + addend
+       movl    _a+0x1234(%rip), %eax
+
+       # PIC lea
+       leaq    _a(%rip), %rax
+
+       # PIC lea through GOT
+       movq    _a@GOTPCREL(%rip), %rax
+       
+       # PIC access of GOT
+       pushq   _a@GOTPCREL(%rip)
+
+       # PIC lea external through GOT
+       movq    _ax@GOTPCREL(%rip), %rax
+       
+       # PIC external access of GOT
+       pushq   _ax@GOTPCREL(%rip)
+
+       # 1-byte store
+       movb  $0x12, _a(%rip)
+
+       # 4-byte store
+       movl  $0x12345678, _a(%rip)
+       
+       # test local labels
+#      lea L1(%rip), %rax              ### assembler bug
+#      movl L0(%rip), %eax             ### assembler bug
+
+       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:
@@ -202,6 +273,32 @@ Llocal2:
 #endif
 
 
+#if __x86_64__
+       .data
+L0:  .quad _test_branches
+_prev:
+       .quad _test_branches+4
+L1:    .quad _test_branches - _test_diffs
+       .quad _test_branches - _test_diffs + 4
+       .long _test_branches - _test_diffs
+#      .long LCL0-.                            ### assembler bug: content value should be (address(LCL0) - 0x24)
+       .quad L1
+#      .quad L0                                        ### assembler bug: should be internal reloc to L0
+       .quad _test_branches - .
+       .quad _test_branches - L1
+       .quad L1 - _prev                        
+
+# the following generates: _foo cannot be undefined in a subtraction expression
+# but it should be ok (it will be a linker error if _foo and _bar are not in same linkage unit)
+#      .quad _foo - _bar       ### assembler bug
+
+       .section __DATA,__data2
+LCL0: .long 2
+
+
+#endif
+
+
        .data
 _a:    
        .long   0
@@ -212,7 +309,7 @@ _b:
        .long   _test_calls+16
        .long   _external
        .long   _external+16
-#elif __ppc64__
+#elif __ppc64__ || __x86_64__
        .quad   _test_calls
        .quad   _test_calls+16
        .quad   _external
index b4007053941ab0b8ae04b7591023e8a0482afa19..610a02b416c872ef9882cb726c241e3008a1aa4d 100644 (file)
@@ -38,9 +38,9 @@ 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}
+       #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}
+       #grep "plus" test-r.${ARCH}.o.dump | ${FAIL_IF_STDIN}
        ${PASS_IFF} diff test.${ARCH}.o.dump test-r.${ARCH}.o.dump
 
 clean:
diff --git a/unit-tests/test-cases/tentative-to-real/Makefile b/unit-tests/test-cases/tentative-to-real/Makefile
new file mode 100644 (file)
index 0000000..2115e7b
--- /dev/null
@@ -0,0 +1,44 @@
+##
+# 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 -r -d
+# will transform a tentative definition into a real one.
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} test.c -c -o test.${ARCH}.o
+       ${LD} -arch ${ARCH} -r test.${ARCH}.o -o test-r.${ARCH}.o
+       ${OBJECTDUMP} test-r.${ARCH}.o | grep tentative | ${PASS_IFF_STDIN}
+       ${LD} -arch ${ARCH} -r -d test.${ARCH}.o -o test-r-d.${ARCH}.o
+       ${OBJECTDUMP} test-r-d.${ARCH}.o | grep tentative | ${PASS_IFF_EMPTY}
+
+clean:
+       rm -rf test.${ARCH}.o test-r.${ARCH}.o 
+       
+
diff --git a/unit-tests/test-cases/tentative-to-real/test.c b/unit-tests/test-cases/tentative-to-real/test.c
new file mode 100644 (file)
index 0000000..87360fc
--- /dev/null
@@ -0,0 +1,3 @@
+
+// a tentative definition
+int a;