]> git.saurik.com Git - apple/ld64.git/blobdiff - src/ld/OutputFile.cpp
ld64-253.9.tar.gz
[apple/ld64.git] / src / ld / OutputFile.cpp
index 963e9e5d89357df276985fba65eb5b19877daf2e..dd0e5b241e8dca5f86c07e6744fc011c30b70e9b 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
  *
- * Copyright (c) 2009-2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2009-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -28,6 +28,8 @@
 #include <sys/stat.h>
 #include <sys/mman.h>
 #include <sys/sysctl.h>
+#include <sys/param.h>
+#include <sys/mount.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <limits.h>
@@ -48,8 +50,8 @@
 #include <vector>
 #include <list>
 #include <algorithm>
-#include <ext/hash_map>
-#include <ext/hash_set>
+#include <unordered_set>
+#include <utility>
 
 #include <CommonCrypto/CommonDigest.h>
 #include <AvailabilityMacros.h>
 #include "LinkEdit.hpp"
 #include "LinkEditClassic.hpp"
 
-
 namespace ld {
 namespace tool {
 
+uint32_t sAdrpNA = 0;
+uint32_t sAdrpNoped = 0;
+uint32_t sAdrpNotNoped = 0;
+
 
 OutputFile::OutputFile(const Options& opts) 
        :
-               hasWeakExternalSymbols(false), usesWeakExternalSymbols(false), overridesWeakExternalSymbols(false), 
-               _noReExportedDylibs(false), hasThreadLocalVariableDefinitions(false), pieDisabled(false), 
+               usesWeakExternalSymbols(false), overridesWeakExternalSymbols(false), 
+               _noReExportedDylibs(false), pieDisabled(false), hasDataInCode(false), 
                headerAndLoadCommandsSection(NULL),
                rebaseSection(NULL), bindingSection(NULL), weakBindingSection(NULL), 
                lazyBindingSection(NULL), exportSection(NULL), 
                splitSegInfoSection(NULL), functionStartsSection(NULL), 
+               dataInCodeSection(NULL), optimizationHintsSection(NULL),
                symbolTableSection(NULL), stringPoolSection(NULL), 
                localRelocationsSection(NULL), externalRelocationsSection(NULL), 
                sectionRelocationsSection(NULL), 
@@ -87,9 +93,11 @@ OutputFile::OutputFile(const Options& opts)
                _hasSectionRelocations(opts.outputKind() == Options::kObjectFile),
                _hasSplitSegInfo(opts.sharedRegionEligible()),
                _hasFunctionStartsInfo(opts.addFunctionStarts()),
+               _hasDataInCodeInfo(opts.addDataInCodeInfo()),
                _hasDynamicSymbolTable(true),
                _hasLocalRelocations(!opts.makeCompressedDyldInfo()),
                _hasExternalRelocations(!opts.makeCompressedDyldInfo()),
+               _hasOptimizationHints(opts.outputKind() == Options::kObjectFile),
                _encryptedTEXTstartOffset(0),
                _encryptedTEXTendOffset(0),
                _localSymbolsStartIndex(0),
@@ -109,7 +117,9 @@ OutputFile::OutputFile(const Options& opts)
                _weakBindingInfoAtom(NULL),
                _exportInfoAtom(NULL),
                _splitSegInfoAtom(NULL),
-               _functionStartsAtom(NULL)
+               _functionStartsAtom(NULL),
+               _dataInCodeAtom(NULL),
+               _optimizationHintsAtom(NULL)
 {
 }
 
@@ -137,14 +147,17 @@ void OutputFile::write(ld::Internal& state)
        this->buildDylibOrdinalMapping(state);
        this->addLoadCommands(state);
        this->addLinkEdit(state);
-       this->setSectionSizesAndAlignments(state);
+       state.setSectionSizesAndAlignments();
        this->setLoadCommandsPadding(state);
-       this->assignFileOffsets(state);
+       _fileSize = state.assignFileOffsets();
        this->assignAtomAddresses(state);
        this->synthesizeDebugNotes(state);
        this->buildSymbolTable(state);
        this->generateLinkEditInfo(state);
-       this->makeSplitSegInfo(state);
+       if ( _options.sharedRegionEncodingV2() )
+               this->makeSplitSegInfoV2(state);
+       else
+               this->makeSplitSegInfo(state);
        this->updateLINKEDITAddresses(state);
        //this->dumpAtomsBySection(state, false);
        this->writeOutputFile(state);
@@ -179,8 +192,11 @@ bool OutputFile::findSegment(ld::Internal& state, uint64_t addr, uint64_t* start
 
 void OutputFile::assignAtomAddresses(ld::Internal& state)
 {
+       const bool log = false;
+       if ( log ) fprintf(stderr, "assignAtomAddresses()\n");
        for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
                ld::Internal::FinalSection* sect = *sit;
+               if ( log ) fprintf(stderr, "  section=%s/%s\n", sect->segmentName(), sect->sectionName());
                for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
                        const ld::Atom* atom = *ait;
                        switch ( sect-> type() ) {
@@ -197,6 +213,7 @@ void OutputFile::assignAtomAddresses(ld::Internal& state)
                                        break;
                                default:
                                        (const_cast<ld::Atom*>(atom))->setSectionStartAddress(sect->address);
+                                       if ( log ) fprintf(stderr, "    atom=%p, addr=0x%08llX, name=%s\n", atom, atom->finalAddress(), atom->name());
                                        break;
                        }
                }
@@ -239,7 +256,19 @@ void OutputFile::updateLINKEDITAddresses(ld::Internal& state)
                _functionStartsAtom->encode();
        }
 
-       // build classic symbol table  
+       if ( _options.addDataInCodeInfo() ) {
+               // build data-in-code info  
+               assert(_dataInCodeAtom != NULL);
+               _dataInCodeAtom->encode();
+       }
+       
+       if ( _hasOptimizationHints ) {
+               // build linker-optimization-hint info  
+               assert(_optimizationHintsAtom != NULL);
+               _optimizationHintsAtom->encode();
+       }
+       
+       // build classic symbol table
        assert(_symbolTableAtom != NULL);
        _symbolTableAtom->encode();
        assert(_indirectSymbolTableAtom != NULL);
@@ -304,65 +333,6 @@ void OutputFile::updateLINKEDITAddresses(ld::Internal& state)
        _fileSize = state.sections.back()->fileOffset + state.sections.back()->size;
 }
 
-void OutputFile::setSectionSizesAndAlignments(ld::Internal& state)
-{
-       for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
-               ld::Internal::FinalSection* sect = *sit;
-               if ( sect->type() == ld::Section::typeAbsoluteSymbols ) {
-                       // absolute symbols need their finalAddress() to their value
-                       for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
-                               const ld::Atom* atom = *ait;
-                               (const_cast<ld::Atom*>(atom))->setSectionOffset(atom->objectAddress());
-                       }
-               }
-               else {
-                       uint16_t maxAlignment = 0;
-                       uint64_t offset = 0;
-                       for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
-                               const ld::Atom* atom = *ait;
-                               if ( atom->alignment().powerOf2 > maxAlignment )
-                                       maxAlignment = atom->alignment().powerOf2;
-                               // calculate section offset for this atom
-                               uint64_t alignment = 1 << atom->alignment().powerOf2;
-                               uint64_t currentModulus = (offset % alignment);
-                               uint64_t requiredModulus = atom->alignment().modulus;
-                               if ( currentModulus != requiredModulus ) {
-                                       if ( requiredModulus > currentModulus )
-                                               offset += requiredModulus-currentModulus;
-                                       else
-                                               offset += requiredModulus+alignment-currentModulus;
-                               }
-                               // LINKEDIT atoms are laid out later
-                               if ( sect->type() != ld::Section::typeLinkEdit ) {
-                                       (const_cast<ld::Atom*>(atom))->setSectionOffset(offset);
-                                       offset += atom->size();
-                               }
-                               if ( (atom->scope() == ld::Atom::scopeGlobal) 
-                                       && (atom->definition() == ld::Atom::definitionRegular) 
-                                       && (atom->combine() == ld::Atom::combineByName) 
-                                       && ((atom->symbolTableInclusion() == ld::Atom::symbolTableIn) 
-                                        || (atom->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip)) ) {
-                                               this->hasWeakExternalSymbols = true;
-                                               if ( _options.warnWeakExports() ) 
-                                                       warning("weak external symbol: %s", atom->name());
-                               }
-                       }
-                       sect->size = offset;
-                       // section alignment is that of a contained atom with the greatest alignment
-                       sect->alignment = maxAlignment;
-                       // unless -sectalign command line option overrides
-                       if  ( _options.hasCustomSectionAlignment(sect->segmentName(), sect->sectionName()) )
-                               sect->alignment = _options.customSectionAlignment(sect->segmentName(), sect->sectionName());
-                       // each atom in __eh_frame has zero alignment to assure they pack together,
-                       // but compilers usually make the CFIs pointer sized, so we want whole section
-                       // to start on pointer sized boundary.
-                       if ( sect->type() == ld::Section::typeCFI )
-                               sect->alignment = 3;
-                       if ( sect->type() == ld::Section::typeTLVDefs )
-                               this->hasThreadLocalVariableDefinitions = true;
-               }
-       }
-}
 
 void OutputFile::setLoadCommandsPadding(ld::Internal& state)
 {
@@ -387,13 +357,16 @@ void OutputFile::setLoadCommandsPadding(ld::Internal& state)
                default:
                        // work backwards from end of segment and lay out sections so that extra room goes to padding atom
                        uint64_t addr = 0;
+                       uint64_t textSegPageSize = _options.segPageSize("__TEXT");
+                       if ( _options.sharedRegionEligible() && (_options.iOSVersionMin() >= ld::iOS_8_0) && (textSegPageSize == 0x4000) )
+                               textSegPageSize = 0x1000;
                        for (std::vector<ld::Internal::FinalSection*>::reverse_iterator it = state.sections.rbegin(); it != state.sections.rend(); ++it) {
                                ld::Internal::FinalSection* sect = *it;
                                if ( strcmp(sect->segmentName(), "__TEXT") != 0 ) 
                                        continue;
                                if ( sect == headerAndLoadCommandsSection ) {
                                        addr -= headerAndLoadCommandsSection->size;
-                                       paddingSize = addr % _options.segmentAlignment();
+                                       paddingSize = addr % textSegPageSize;
                                        break;
                                }
                                addr -= sect->size;
@@ -444,153 +417,6 @@ uint64_t OutputFile::pageAlign(uint64_t addr, uint64_t pageSize)
        return ((addr+pageSize-1) & (-pageSize)); 
 }
 
-
-void OutputFile::assignFileOffsets(ld::Internal& state)
-{
-       const bool log = false;
-       const bool hiddenSectionsOccupyAddressSpace = ((_options.outputKind() != Options::kObjectFile)
-                                                                                               && (_options.outputKind() != Options::kPreload));
-       const bool segmentsArePageAligned = (_options.outputKind() != Options::kObjectFile);
-
-       uint64_t address = 0;
-       const char* lastSegName = "";
-       uint64_t floatingAddressStart = _options.baseAddress();
-       
-       // first pass, assign addresses to sections in segments with fixed start addresses
-       if ( log ) fprintf(stderr, "Fixed address segments:\n");
-       for (std::vector<ld::Internal::FinalSection*>::iterator it = state.sections.begin(); it != state.sections.end(); ++it) {
-               ld::Internal::FinalSection* sect = *it;
-               if ( ! _options.hasCustomSegmentAddress(sect->segmentName()) ) 
-                       continue;
-               if ( segmentsArePageAligned ) {
-                       if ( strcmp(lastSegName, sect->segmentName()) != 0 ) {
-                               address = _options.customSegmentAddress(sect->segmentName());
-                               lastSegName = sect->segmentName();
-                       }
-               }
-               // adjust section address based on alignment
-               uint64_t unalignedAddress = address;
-               uint64_t alignment = (1 << sect->alignment);
-               address = ( (unalignedAddress+alignment-1) & (-alignment) );
-       
-               // update section info
-               sect->address = address;
-               sect->alignmentPaddingBytes = (address - unalignedAddress);
-               
-               // sanity check size
-               if ( ((address + sect->size) > _options.maxAddress()) && (_options.outputKind() != Options::kObjectFile) 
-                                                                                                                         && (_options.outputKind() != Options::kStaticExecutable) )
-                       throwf("section %s (address=0x%08llX, size=%llu) would make the output executable exceed available address range", 
-                                               sect->sectionName(), address, sect->size);
-               
-               if ( log ) fprintf(stderr, "  address=0x%08llX, hidden=%d, alignment=%02d, section=%s,%s\n",
-                                               sect->address, sect->isSectionHidden(), sect->alignment, sect->segmentName(), sect->sectionName());
-               // update running totals
-               if ( !sect->isSectionHidden() || hiddenSectionsOccupyAddressSpace )
-                       address += sect->size;
-               
-               // if TEXT segment address is fixed, then flow other segments after it
-               if ( strcmp(sect->segmentName(), "__TEXT") == 0 ) {
-                       floatingAddressStart = address;
-               }
-       }
-       
-       // second pass, assign section address to sections in segments that are contiguous with previous segment
-       address = floatingAddressStart;
-       lastSegName = "";
-       if ( log ) fprintf(stderr, "Regular layout segments:\n");
-       for (std::vector<ld::Internal::FinalSection*>::iterator it = state.sections.begin(); it != state.sections.end(); ++it) {
-               ld::Internal::FinalSection* sect = *it;
-               if ( _options.hasCustomSegmentAddress(sect->segmentName()) ) 
-                       continue;
-               if ( (_options.outputKind() == Options::kPreload) && (sect->type() == ld::Section::typeMachHeader) ) {
-                       sect->alignmentPaddingBytes = 0;
-                       continue;
-               }
-               if ( segmentsArePageAligned ) {
-                       if ( strcmp(lastSegName, sect->segmentName()) != 0 ) {
-                               // round up size of last segment if needed
-                               if ( *lastSegName != '\0' ) {
-                                       address = pageAlign(address, _options.segPageSize(lastSegName));
-                               }
-                               // set segment address based on end of last segment
-                               address = pageAlign(address);
-                               lastSegName = sect->segmentName();
-                       }
-               }
-               // adjust section address based on alignment
-               uint64_t unalignedAddress = address;
-               uint64_t alignment = (1 << sect->alignment);
-               address = ( (unalignedAddress+alignment-1) & (-alignment) );
-       
-               // update section info
-               sect->address = address;
-               sect->alignmentPaddingBytes = (address - unalignedAddress);
-               
-               // sanity check size
-               if ( ((address + sect->size) > _options.maxAddress()) && (_options.outputKind() != Options::kObjectFile) 
-                                                                                                                         && (_options.outputKind() != Options::kStaticExecutable) )
-                               throwf("section %s (address=0x%08llX, size=%llu) would make the output executable exceed available address range", 
-                                               sect->sectionName(), address, sect->size);
-               
-               if ( log ) fprintf(stderr, "  address=0x%08llX, hidden=%d, alignment=%02d, padBytes=%d, section=%s,%s\n",
-                                                       sect->address, sect->isSectionHidden(), sect->alignment, sect->alignmentPaddingBytes, 
-                                                       sect->segmentName(), sect->sectionName());
-               // update running totals
-               if ( !sect->isSectionHidden() || hiddenSectionsOccupyAddressSpace )
-                       address += sect->size;
-       }
-       
-       
-       // third pass, assign section file offsets 
-       uint64_t fileOffset = 0;
-       lastSegName = "";
-       if ( log ) fprintf(stderr, "All segments with file offsets:\n");
-       for (std::vector<ld::Internal::FinalSection*>::iterator it = state.sections.begin(); it != state.sections.end(); ++it) {
-               ld::Internal::FinalSection* sect = *it;
-               if ( hasZeroForFileOffset(sect) ) {
-                       // fileoff of zerofill sections is moot, but historically it is set to zero
-                       sect->fileOffset = 0;
-               }
-               else {
-                       // page align file offset at start of each segment
-                       if ( segmentsArePageAligned && (*lastSegName != '\0') && (strcmp(lastSegName, sect->segmentName()) != 0) ) {
-                               fileOffset = pageAlign(fileOffset, _options.segPageSize(lastSegName));
-                       }
-                       lastSegName = sect->segmentName();
-
-                       // align file offset with address layout
-                       fileOffset += sect->alignmentPaddingBytes;
-                       
-                       // update section info
-                       sect->fileOffset = fileOffset;
-                       
-                       // update running total
-                       fileOffset += sect->size;
-               }
-               
-               if ( log ) fprintf(stderr, "  fileoffset=0x%08llX, address=0x%08llX, hidden=%d, size=%lld, alignment=%02d, section=%s,%s\n",
-                               sect->fileOffset, sect->address, sect->isSectionHidden(), sect->size, sect->alignment, 
-                               sect->segmentName(), sect->sectionName());
-       }
-
-
-       // for encrypted iPhoneOS apps
-       if ( _options.makeEncryptable() ) { 
-               // remember end of __TEXT for later use by load command
-               for (std::vector<ld::Internal::FinalSection*>::iterator it = state.sections.begin(); it != state.sections.end(); ++it) {
-                       ld::Internal::FinalSection* sect = *it;
-                       if ( strcmp(sect->segmentName(), "__TEXT") == 0 ) {
-                               _encryptedTEXTendOffset = pageAlign(sect->fileOffset);
-                       }
-               }
-       }
-
-       // remember total file size
-       _fileSize = fileOffset;
-}
-
-
 static const char* makeName(const ld::Atom& atom)
 {
        static char buffer[4096];
@@ -659,6 +485,11 @@ uint64_t OutputFile::addressOf(const ld::Internal& state, const ld::Fixup* fixup
                        return (*target)->finalAddress();
                case ld::Fixup::bindingsIndirectlyBound:
                        *target = state.indirectBindingTable[fixup->u.bindingIndex];
+               #ifndef NDEBUG
+                       if ( ! (*target)->finalAddressMode() ) {
+                               throwf("reference to symbol (which has not been assigned an address) %s", (*target)->name());
+                       }
+               #endif
                        return (*target)->finalAddress();
        }
        throw "unexpected binding";
@@ -773,16 +604,49 @@ void OutputFile::rangeCheckBranch32(int64_t displacement, ld::Internal& state, c
                printSectionLayout(state);
                
                const ld::Atom* target; 
-               throwf("32-bit branch out of range (%lld max is +/-4GB): from %s (0x%08llX) to %s (0x%08llX)", 
+               throwf("32-bit branch out of range (%lld max is +/-2GB): from %s (0x%08llX) to %s (0x%08llX)",
                                displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup), 
                                addressOf(state, fixup, &target));
        }
 }
 
+
+void OutputFile::rangeCheckAbsolute32(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
+{
+       const int64_t fourGigLimit  = 0xFFFFFFFF;
+       if ( displacement > fourGigLimit ) {
+               // <rdar://problem/9610466> cannot enforce 32-bit range checks on 32-bit archs because assembler loses sign information
+               //  .long _foo - 0xC0000000
+               // is encoded in mach-o the same as:
+               //  .long _foo + 0x40000000
+               // so if _foo lays out to 0xC0000100, the first is ok, but the second is not.  
+               if ( (_options.architecture() == CPU_TYPE_ARM) || (_options.architecture() == CPU_TYPE_I386) ) {
+                       // Unlikely userland code does funky stuff like this, so warn for them, but not warn for -preload or -static
+                       if ( (_options.outputKind() != Options::kPreload) && (_options.outputKind() != Options::kStaticExecutable) ) {
+                               warning("32-bit absolute address out of range (0x%08llX max is 4GB): from %s + 0x%08X (0x%08llX) to 0x%08llX", 
+                                               displacement, atom->name(), fixup->offsetInAtom, atom->finalAddress(), displacement);
+                       }
+                       return;
+               }
+               // show layout of final image
+               printSectionLayout(state);
+               
+               const ld::Atom* target; 
+               if ( fixup->binding == ld::Fixup::bindingNone )
+                       throwf("32-bit absolute address out of range (0x%08llX max is 4GB): from %s + 0x%08X (0x%08llX) to 0x%08llX", 
+                               displacement, atom->name(), fixup->offsetInAtom, atom->finalAddress(), displacement);
+               else
+                       throwf("32-bit absolute address out of range (0x%08llX max is 4GB): from %s + 0x%08X (0x%08llX) to %s (0x%08llX)", 
+                               displacement, atom->name(), fixup->offsetInAtom, atom->finalAddress(), referenceTargetAtomName(state, fixup), 
+                               addressOf(state, fixup, &target));
+       }
+}
+
+
 void OutputFile::rangeCheckRIP32(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
 {
        const int64_t twoGigLimit  = 0x7FFFFFFF;
-       if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) {
+       if ( (displacement > twoGigLimit) || (displacement < (-twoGigLimit)) ) {        
                // show layout of final image
                printSectionLayout(state);
                
@@ -806,78 +670,93 @@ void OutputFile::rangeCheckARM12(int64_t displacement, ld::Internal& state, cons
        }
 }
 
+bool OutputFile::checkArmBranch24Displacement(int64_t displacement)
+{
+       return ( (displacement < 33554428LL) && (displacement > (-33554432LL)) );
+}
 
 void OutputFile::rangeCheckARMBranch24(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
 {
-       if ( (displacement > 33554428LL) || (displacement < (-33554432LL)) ) {
-               // show layout of final image
-               printSectionLayout(state);
+       if ( checkArmBranch24Displacement(displacement) )
+               return;
                
-               const ld::Atom* target; 
-               throwf("b/bl/blx ARM branch out of range (%lld max is +/-32MB): from %s (0x%08llX) to %s (0x%08llX)", 
-                               displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup), 
-                               addressOf(state, fixup, &target));
-       }
+       // show layout of final image
+       printSectionLayout(state);
+       
+       const ld::Atom* target; 
+       throwf("b/bl/blx ARM branch out of range (%lld max is +/-32MB): from %s (0x%08llX) to %s (0x%08llX)", 
+                       displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup), 
+                       addressOf(state, fixup, &target));
 }
 
-void OutputFile::rangeCheckThumbBranch22(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
+bool OutputFile::checkThumbBranch22Displacement(int64_t displacement)
 {
-       // armv7 supports a larger displacement
-       if ( _options.preferSubArchitecture() && (_options.subArchitecture() == CPU_SUBTYPE_ARM_V7) ) {
+       // thumb2 supports  +/- 16MB displacement
+       if ( _options.preferSubArchitecture() && _options.archSupportsThumb2() ) {
                if ( (displacement > 16777214LL) || (displacement < (-16777216LL)) ) {
-                       // show layout of final image
-                       printSectionLayout(state);
-                       
-                       const ld::Atom* target; 
-                       throwf("b/bl/blx thumb2 branch out of range (%lld max is +/-16MB): from %s (0x%08llX) to %s (0x%08llX)", 
-                                       displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup), 
-                               addressOf(state, fixup, &target));
+                       return false;
                }
        }
        else {
+               // thumb1 supports +/- 4MB displacement
                if ( (displacement > 4194302LL) || (displacement < (-4194304LL)) ) {
-                       // show layout of final image
-                       printSectionLayout(state);
-                       
-                       const ld::Atom* target; 
-                       throwf("b/bl/blx thumb1 branch out of range (%lld max is +/-4MB): from %s (0x%08llX) to %s (0x%08llX)", 
-                                       displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup), 
-                               addressOf(state, fixup, &target));
+                       return false;
                }
        }
+       return true;
+}
+
+void OutputFile::rangeCheckThumbBranch22(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
+{
+       if ( checkThumbBranch22Displacement(displacement) )
+               return;
+
+       // show layout of final image
+       printSectionLayout(state);
+
+       const ld::Atom* target; 
+       if ( _options.preferSubArchitecture() && _options.archSupportsThumb2() ) {
+               throwf("b/bl/blx thumb2 branch out of range (%lld max is +/-16MB): from %s (0x%08llX) to %s (0x%08llX)", 
+                               displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup), 
+                               addressOf(state, fixup, &target));
+       }
+       else {
+               throwf("b/bl/blx thumb1 branch out of range (%lld max is +/-4MB): from %s (0x%08llX) to %s (0x%08llX)", 
+                               displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup), 
+                               addressOf(state, fixup, &target));
+       }
 }
 
-void OutputFile::rangeCheckPPCBranch24(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
+
+void OutputFile::rangeCheckARM64Branch26(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
 {
-       const int64_t bl_eightMegLimit = 0x00FFFFFF;
-       if ( (displacement > bl_eightMegLimit) || (displacement < (-bl_eightMegLimit)) ) {
+       const int64_t bl_128MegLimit = 0x07FFFFFF;
+       if ( (displacement > bl_128MegLimit) || (displacement < (-bl_128MegLimit)) ) {
                // show layout of final image
                printSectionLayout(state);
                
                const ld::Atom* target; 
-               throwf("bl PPC branch out of range (%lld max is +/-16MB): from %s (0x%08llX) to %s (0x%08llX)", 
+               throwf("b(l) ARM64 branch out of range (%lld max is +/-128MB): from %s (0x%08llX) to %s (0x%08llX)", 
                                displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup), 
                                addressOf(state, fixup, &target));
        }
 }
 
-void OutputFile::rangeCheckPPCBranch14(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
+void OutputFile::rangeCheckARM64Page21(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
 {
-       const int64_t b_sixtyFourKiloLimit = 0x0000FFFF;
-       if ( (displacement > b_sixtyFourKiloLimit) || (displacement < (-b_sixtyFourKiloLimit)) ) {
+       const int64_t adrp_4GigLimit = 0x100000000ULL;
+       if ( (displacement > adrp_4GigLimit) || (displacement < (-adrp_4GigLimit)) ) {
                // show layout of final image
                printSectionLayout(state);
                
                const ld::Atom* target; 
-               throwf("bcc PPC branch out of range (%lld max is +/-64KB): from %s (0x%08llX) to %s (0x%08llX)", 
+               throwf("ARM64 ADRP out of range (%lld max is +/-4GB): from %s (0x%08llX) to %s (0x%08llX)", 
                                displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup), 
                                addressOf(state, fixup, &target));
        }
 }
 
 
-
-
 uint16_t OutputFile::get16LE(uint8_t* loc) { return LittleEndian::get16(*(uint16_t*)loc); }
 void     OutputFile::set16LE(uint8_t* loc, uint16_t value) { LittleEndian::set16(*(uint16_t*)loc, value); }
 
@@ -896,141 +775,672 @@ void     OutputFile::set32BE(uint8_t* loc, uint32_t value) { BigEndian::set32(*(
 uint64_t OutputFile::get64BE(uint8_t* loc) { return BigEndian::get64(*(uint64_t*)loc); }
 void     OutputFile::set64BE(uint8_t* loc, uint64_t value) { BigEndian::set64(*(uint64_t*)loc, value); }
 
-void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::Atom* atom, uint8_t* buffer)
+#if SUPPORT_ARCH_arm64
+
+static uint32_t makeNOP() {
+       return 0xD503201F;
+}
+
+enum SignExtension { signedNot, signed32, signed64 };
+struct LoadStoreInfo {
+       uint32_t                reg;
+       uint32_t                baseReg;
+       uint32_t                offset;         // after scaling
+       uint32_t                size;           // 1,2,4,8, or 16
+       bool                    isStore;
+       bool                    isFloat;        // if destReg is FP/SIMD
+       SignExtension   signEx;         // if load is sign extended
+};
+
+static uint32_t makeLDR_literal(const LoadStoreInfo& info, uint64_t targetAddress, uint64_t instructionAddress) 
 {
-       //fprintf(stderr, "applyFixUps() on %s\n", atom->name());
-       int64_t accumulator = 0;
-       const ld::Atom* toTarget = NULL;        
-       const ld::Atom* fromTarget;
-       int64_t delta;
-       uint32_t instruction;
-       uint32_t newInstruction;
-       uint16_t instructionLowHalf;
-       bool is_bl;
-       bool is_blx;
-       bool is_b;
-       bool thumbTarget = false;
-       for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
-               uint8_t* fixUpLocation = &buffer[fit->offsetInAtom];
-               switch ( (ld::Fixup::Kind)(fit->kind) ) { 
-                       case ld::Fixup::kindNone:
-                       case ld::Fixup::kindNoneFollowOn:
-                       case ld::Fixup::kindNoneGroupSubordinate:
-                       case ld::Fixup::kindNoneGroupSubordinateFDE:
-                       case ld::Fixup::kindNoneGroupSubordinateLSDA:
-                       case ld::Fixup::kindNoneGroupSubordinatePersonality:
-                               break;
-                       case ld::Fixup::kindSetTargetAddress:
-                               accumulator = addressOf(state, fit, &toTarget);                 
-                               thumbTarget = targetIsThumb(state, fit);
-                               if ( thumbTarget ) 
-                                       accumulator |= 1;
-                               if ( fit->contentAddendOnly || fit->contentDetlaToAddendOnly )
-                                       accumulator = 0;
-                               break;
-                       case ld::Fixup::kindSubtractTargetAddress:
-                               delta = addressOf(state, fit, &fromTarget);
-                               if ( ! fit->contentAddendOnly )
-                                       accumulator -= delta;
-                               break;
-                       case ld::Fixup::kindAddAddend:
-                               // <rdar://problem/8342028> ARM main executables main contain .long constants pointing
-                               // into themselves such as jump tables.  These .long should not have thumb bit set
-                               // even though the target is a thumb instruction. We can tell it is an interior pointer
-                               // because we are processing an addend. 
-                               if ( thumbTarget && (toTarget == atom) && ((int32_t)fit->u.addend > 0) ) {
-                                       accumulator &= (-2);
-                                       //warning("removing thumb bit from intra-atom pointer in %s %s+0x%0X", 
-                                       //              atom->section().sectionName(), atom->name(), fit->offsetInAtom);
-                               }
-                               accumulator += fit->u.addend;
-                               break;
-                       case ld::Fixup::kindSubtractAddend:
-                               accumulator -= fit->u.addend;
-                               break;
-                       case ld::Fixup::kindSetTargetImageOffset:
-                               accumulator = addressOf(state, fit, &toTarget) - mhAddress;
-                               break;
-                       case ld::Fixup::kindSetTargetSectionOffset:
-                               accumulator = sectionOffsetOf(state, fit);
-                               break;
-                       case ld::Fixup::kindSetTargetTLVTemplateOffset:
-                               accumulator = tlvTemplateOffsetOf(state, fit);
-                               break;
-                       case ld::Fixup::kindStore8:
-                               *fixUpLocation += accumulator;
-                               break;
-                       case ld::Fixup::kindStoreLittleEndian16:
-                               set16LE(fixUpLocation, accumulator);
-                               break;
-                       case ld::Fixup::kindStoreLittleEndianLow24of32:
-                               set32LE(fixUpLocation, (get32LE(fixUpLocation) & 0xFF000000) | (accumulator & 0x00FFFFFF) );
-                               break;
-                       case ld::Fixup::kindStoreLittleEndian32:
-                               set32LE(fixUpLocation, accumulator);
-                               break;
-                       case ld::Fixup::kindStoreLittleEndian64:
-                               set64LE(fixUpLocation, accumulator);
-                               break;
-                       case ld::Fixup::kindStoreBigEndian16:
-                               set16BE(fixUpLocation, accumulator);
-                               break;
-                       case ld::Fixup::kindStoreBigEndianLow24of32:
-                               set32BE(fixUpLocation, (get32BE(fixUpLocation) & 0xFF000000) | (accumulator & 0x00FFFFFF) );
-                               break;
-                       case ld::Fixup::kindStoreBigEndian32:
-                               set32BE(fixUpLocation, accumulator);
-                               break;
-                       case ld::Fixup::kindStoreBigEndian64:
-                               set64BE(fixUpLocation, accumulator);
-                               break;
-                       case ld::Fixup::kindStoreX86PCRel8:
-                       case ld::Fixup::kindStoreX86BranchPCRel8:
-                               if ( fit->contentAddendOnly )
-                                       delta = accumulator;
-                               else
-                                       delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 1);
-                               rangeCheck8(delta, state, atom, fit);
-                               *fixUpLocation = delta;
-                               break;
-                       case ld::Fixup::kindStoreX86PCRel16:
-                               if ( fit->contentAddendOnly )
-                                       delta = accumulator;
-                               else
-                                       delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 2);
-                               rangeCheck16(delta, state, atom, fit);
-                               set16LE(fixUpLocation, delta);
-                               break;
-                       case ld::Fixup::kindStoreX86BranchPCRel32:
-                               if ( fit->contentAddendOnly )
-                                       delta = accumulator;
-                               else
-                                       delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 4);
-                               rangeCheckBranch32(delta, state, atom, fit);
-                               set32LE(fixUpLocation, delta);
-                               break;
-                       case ld::Fixup::kindStoreX86PCRel32GOTLoad:
-                       case ld::Fixup::kindStoreX86PCRel32GOT:
-                       case ld::Fixup::kindStoreX86PCRel32:
-                       case ld::Fixup::kindStoreX86PCRel32TLVLoad:
-                               if ( fit->contentAddendOnly )
-                                       delta = accumulator;
-                               else
-                                       delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 4);
-                               rangeCheckRIP32(delta, state, atom, fit);
-                               set32LE(fixUpLocation, delta);
-                               break;
-                       case ld::Fixup::kindStoreX86PCRel32_1:
-                               if ( fit->contentAddendOnly )
-                                       delta = accumulator - 1;
-                               else
-                                       delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 5);
-                               rangeCheckRIP32(delta, state, atom, fit);
-                               set32LE(fixUpLocation, delta);
-                               break;
-                       case ld::Fixup::kindStoreX86PCRel32_2:
-                               if ( fit->contentAddendOnly )
-                                       delta = accumulator - 2;
+       int64_t delta = targetAddress - instructionAddress;
+       assert(delta < 1024*1024);
+       assert(delta > -1024*1024);
+       assert((info.reg & 0xFFFFFFE0) == 0);
+       assert((targetAddress & 0x3) == 0);
+       assert((instructionAddress & 0x3) == 0);
+       assert(!info.isStore);
+       uint32_t imm19 = (delta << 3) & 0x00FFFFE0;
+       uint32_t instruction = 0;
+       switch ( info.size ) {
+               case 4:
+                       if ( info.isFloat ) {
+                               assert(info.signEx == signedNot);
+                               instruction = 0x1C000000;
+                       }
+                       else {
+                               if ( info.signEx == signed64 )
+                                       instruction = 0x98000000;
+                               else
+                                       instruction = 0x18000000;
+                       }
+                       break;
+               case 8:
+                       assert(info.signEx == signedNot);
+                       instruction = info.isFloat ? 0x5C000000 : 0x58000000;
+                       break;
+               case 16:
+                       assert(info.signEx == signedNot);
+                       instruction = 0x9C000000;
+                       break;
+               default:
+                       assert(0 && "invalid load size for literal");
+       }
+       return (instruction | imm19 | info.reg);
+}
+
+static uint32_t makeADR(uint32_t destReg, uint64_t targetAddress, uint64_t instructionAddress)
+{
+       assert((destReg & 0xFFFFFFE0) == 0);
+       assert((instructionAddress & 0x3) == 0);
+       uint32_t instruction = 0x10000000;
+       int64_t delta = targetAddress - instructionAddress;
+       assert(delta < 1024*1024);
+       assert(delta > -1024*1024);
+       uint32_t immhi = (delta & 0x001FFFFC) << 3;
+       uint32_t immlo = (delta & 0x00000003) << 29;
+       return (instruction | immhi | immlo | destReg); 
+}
+
+static uint32_t makeLoadOrStore(const LoadStoreInfo& info)
+{
+       uint32_t instruction = 0x39000000;
+       if ( info.isFloat )
+               instruction |= 0x04000000;
+       instruction |= info.reg;
+       instruction |= (info.baseReg << 5);
+       uint32_t sizeBits = 0;
+       uint32_t opcBits = 0;
+       uint32_t imm12Bits = 0;
+       switch ( info.size ) {
+               case 1:
+                       sizeBits = 0;
+                       imm12Bits = info.offset;
+                       if ( info.isStore ) {
+                               opcBits = 0;
+                       }
+                       else {
+                               switch ( info.signEx ) {
+                                       case signedNot:
+                                               opcBits = 1;
+                                               break;
+                                       case signed32:
+                                               opcBits = 3;
+                                               break;
+                                       case signed64:
+                                               opcBits = 2;
+                                               break;
+                               }
+                       }
+                       break;
+               case 2:
+                       sizeBits = 1;
+                       assert((info.offset % 2) == 0);
+                       imm12Bits = info.offset/2;
+                       if ( info.isStore ) {
+                               opcBits = 0;
+                       }
+                       else {
+                               switch ( info.signEx ) {
+                                       case signedNot:
+                                               opcBits = 1;
+                                               break;
+                                       case signed32:
+                                               opcBits = 3;
+                                               break;
+                                       case signed64:
+                                               opcBits = 2;
+                                               break;
+                               }
+                       }
+                       break;
+               case 4:
+                       sizeBits = 2;
+                       assert((info.offset % 4) == 0);
+                       imm12Bits = info.offset/4;
+                       if ( info.isStore ) {
+                               opcBits = 0;
+                       }
+                       else {
+                               switch ( info.signEx ) {
+                                       case signedNot:
+                                               opcBits = 1;
+                                               break;
+                                       case signed32:
+                                               assert(0 && "cannot use signed32 with 32-bit load/store");
+                                               break;
+                                       case signed64:
+                                               opcBits = 2;
+                                               break;
+                               }
+                       }
+                       break;
+               case 8:
+                       sizeBits = 3;
+                       assert((info.offset % 8) == 0);
+                       imm12Bits = info.offset/8;
+                       if ( info.isStore ) {
+                               opcBits = 0;
+                       }
+                       else {
+                               opcBits = 1;
+                               assert(info.signEx == signedNot);
+                       }
+                       break;
+               case 16:
+                       sizeBits = 0;
+                       assert((info.offset % 16) == 0);
+                       imm12Bits = info.offset/16;
+                       assert(info.isFloat);
+                       if ( info.isStore ) {
+                               opcBits = 2;
+                       }
+                       else {
+                               opcBits = 3;
+                       }
+                       break;
+               default:
+                       assert(0 && "bad load/store size");
+                       break;
+       }
+       assert(imm12Bits < 4096);
+       return (instruction | (sizeBits << 30) | (opcBits << 22) | (imm12Bits << 10));
+}
+
+static bool parseLoadOrStore(uint32_t instruction, LoadStoreInfo& info) 
+{
+       if ( (instruction & 0x3B000000) != 0x39000000 ) 
+               return false;
+       info.isFloat = ( (instruction & 0x04000000) != 0 );
+       info.reg = (instruction & 0x1F);
+       info.baseReg = ((instruction>>5) & 0x1F);
+       switch (instruction & 0xC0C00000) {
+               case 0x00000000:
+                       info.size = 1;
+                       info.isStore = true;
+                       info.signEx = signedNot;
+                       break;
+               case 0x00400000:
+                       info.size = 1;
+                       info.isStore = false;
+                       info.signEx = signedNot;
+                       break;
+               case 0x00800000:
+                       if ( info.isFloat ) {
+                               info.size = 16;
+                               info.isStore = true;
+                               info.signEx = signedNot;
+                       }
+                       else {
+                               info.size = 1;
+                               info.isStore = false;
+                               info.signEx = signed64;
+                       }
+                       break;
+               case 0x00C00000:
+                       if ( info.isFloat ) {
+                               info.size = 16;
+                               info.isStore = false;
+                               info.signEx = signedNot;
+                       }
+                       else {
+                               info.size = 1;
+                               info.isStore = false;
+                               info.signEx = signed32;
+                       }
+                       break;
+               case 0x40000000:
+                       info.size = 2;
+                       info.isStore = true;
+                       info.signEx = signedNot;
+                       break;
+               case 0x40400000:
+                       info.size = 2;
+                       info.isStore = false;
+                       info.signEx = signedNot;
+                       break;
+               case 0x40800000:
+                       info.size = 2;
+                       info.isStore = false;
+                       info.signEx = signed64;
+                       break;
+               case 0x40C00000:
+                       info.size = 2;
+                       info.isStore = false;
+                       info.signEx = signed32;
+                       break;
+               case 0x80000000:
+                       info.size = 4;
+                       info.isStore = true;
+                       info.signEx = signedNot;
+                       break;
+               case 0x80400000:
+                       info.size = 4;
+                       info.isStore = false;
+                       info.signEx = signedNot;
+                       break;
+               case 0x80800000:
+                       info.size = 4;
+                       info.isStore = false;
+                       info.signEx = signed64;
+                       break;
+               case 0xC0000000:
+                       info.size = 8;
+                       info.isStore = true;
+                       info.signEx = signedNot;
+                       break;
+               case 0xC0400000:
+                       info.size = 8;
+                       info.isStore = false;
+                       info.signEx = signedNot;
+                       break;
+               default:
+                       return false;
+       }
+       info.offset = ((instruction >> 10) & 0x0FFF) * info.size;
+       return true;    
+}
+
+struct AdrpInfo {
+       uint32_t        destReg;
+};
+
+static bool parseADRP(uint32_t instruction, AdrpInfo& info) 
+{
+       if ( (instruction & 0x9F000000) != 0x90000000 )
+               return false;
+       info.destReg = (instruction & 0x1F);
+       return true;
+}
+
+struct AddInfo {
+       uint32_t        destReg;
+       uint32_t        srcReg;
+       uint32_t        addend;
+};
+
+static bool parseADD(uint32_t instruction, AddInfo& info) 
+{
+       if ( (instruction & 0xFFC00000) != 0x91000000 )
+               return false;
+       info.destReg = (instruction & 0x1F);
+       info.srcReg = ((instruction>>5) & 0x1F);
+       info.addend = ((instruction>>10) & 0xFFF);
+       return true;
+}
+
+
+
+#if 0
+static uint32_t makeLDR_scaledOffset(const LoadStoreInfo& info) 
+{
+       assert((info.reg & 0xFFFFFFE0) == 0);
+       assert((info.baseReg & 0xFFFFFFE0) == 0);
+       assert(!info.isFloat || (info.signEx != signedNot));
+       uint32_t sizeBits = 0;
+       uint32_t opcBits = 1;
+       uint32_t vBit = info.isFloat;
+       switch ( info.signEx ) {
+               case signedNot:
+                       opcBits = 1;
+                       break;
+               case signed32:
+                       opcBits = 3;
+                       break;
+               case signed64:
+                       opcBits = 2;
+                       break;
+               default:
+                       assert(0 && "bad SignExtension runtime value");
+       }
+       switch ( info.size ) {
+               case 1:
+                       sizeBits = 0;
+                       break;
+               case 2:
+                       sizeBits = 1;
+                       break;
+               case 4:
+                       sizeBits = 2;
+                       break;
+               case 8:
+                       sizeBits = 3;
+                       break;
+               case 16:
+                       sizeBits = 0;
+                       vBit = 1;
+                       opcBits = 3;
+                       break;
+               default:
+                       assert(0 && "invalid load size for literal");
+       }
+       assert((info.offset % info.size) == 0);
+       uint32_t scaledOffset = info.offset/info.size;
+       assert(scaledOffset < 4096);
+       return (0x39000000 | (sizeBits<<30) | (vBit<<26) | (opcBits<<22) | (scaledOffset<<10) | (info.baseReg<<5) | info.reg);
+}
+
+static uint32_t makeLDR_literal(uint32_t destReg, uint32_t loadSize, bool isFloat, uint64_t targetAddress, uint64_t instructionAddress) 
+{
+       int64_t delta = targetAddress - instructionAddress;
+       assert(delta < 1024*1024);
+       assert(delta > -1024*1024);
+       assert((destReg & 0xFFFFFFE0) == 0);
+       assert((targetAddress & 0x3) == 0);
+       assert((instructionAddress & 0x3) == 0);
+       uint32_t imm19 = (delta << 3) & 0x00FFFFE0;
+       uint32_t instruction = 0;
+       switch ( loadSize ) {
+               case 4:
+                       instruction = isFloat ? 0x1C000000 : 0x18000000;
+                       break;
+               case 8:
+                       instruction = isFloat ? 0x5C000000 : 0x58000000;
+                       break;
+               case 16:
+                       instruction = 0x9C000000;
+                       break;
+               default:
+                       assert(0 && "invalid load size for literal");
+       }
+       return (instruction | imm19 | destReg);
+}
+
+
+static bool ldrInfo(uint32_t instruction, uint8_t* size, uint8_t* destReg, bool* v, uint32_t* scaledOffset)
+{
+       *v = ( (instruction & 0x04000000) != 0 );
+       *destReg = (instruction & 0x1F);
+       uint32_t imm12 = ((instruction >> 10) & 0x00000FFF);
+       switch ( (instruction & 0xC0000000) >> 30 ) {
+               case 0:
+                       // vector and byte LDR have same "size" bits, need to check other bits to differenciate
+                       if ( (instruction & 0x00800000) == 0 ) {
+                               *size = 1;
+                               *scaledOffset = imm12;
+                       }
+                       else {
+                               *size = 16;
+                               *scaledOffset = imm12 * 16;
+                       }
+                       break;
+               case 1:
+                       *size = 2;
+                       *scaledOffset = imm12 * 2;
+                       break;
+               case 2:
+                       *size = 4;
+                       *scaledOffset = imm12 * 4;
+                       break;
+               case 3:
+                       *size = 8;
+                       *scaledOffset = imm12 * 8;
+                       break;
+       }
+       return ((instruction & 0x3B400000) == 0x39400000);
+}
+#endif
+
+static bool withinOneMeg(uint64_t addr1, uint64_t addr2) {
+       int64_t delta = (addr2 - addr1);
+       return ( (delta < 1024*1024) && (delta > -1024*1024) );
+}
+#endif // SUPPORT_ARCH_arm64
+
+void OutputFile::setInfo(ld::Internal& state, const ld::Atom* atom, uint8_t* buffer, const std::map<uint32_t, const Fixup*>& usedByHints, 
+                                               uint32_t offsetInAtom, uint32_t delta, InstructionInfo* info) 
+{
+       info->offsetInAtom = offsetInAtom + delta;
+       std::map<uint32_t, const Fixup*>::const_iterator pos = usedByHints.find(info->offsetInAtom);
+       if ( (pos != usedByHints.end()) && (pos->second != NULL) ) {
+               info->fixup = pos->second;
+               info->targetAddress = addressOf(state, info->fixup, &info->target);
+               if ( info->fixup->clusterSize != ld::Fixup::k1of1 ) {
+                       assert(info->fixup->firstInCluster());
+                       const ld::Fixup* nextFixup = info->fixup + 1;
+                       if ( nextFixup->kind == ld::Fixup::kindAddAddend ) {
+                               info->targetAddress += nextFixup->u.addend;
+                       }
+                       else {
+                               assert(0 && "expected addend");
+                       }
+               }
+       }
+       else {
+               info->fixup = NULL;
+               info->targetAddress = 0;
+               info->target = NULL;
+       }
+       info->instructionContent = &buffer[info->offsetInAtom];
+       info->instructionAddress = atom->finalAddress() + info->offsetInAtom;
+       info->instruction = get32LE(info->instructionContent);
+}      
+
+#if SUPPORT_ARCH_arm64
+static bool isPageKind(const ld::Fixup* fixup, bool mustBeGOT=false)
+{
+       if ( fixup == NULL )
+               return false;
+       const ld::Fixup* f;
+       switch ( fixup->kind ) {
+               case ld::Fixup::kindStoreTargetAddressARM64Page21:
+                       return !mustBeGOT;
+               case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
+               case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21:
+               case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPage21:
+               case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPage21:
+                       return true;
+               case ld::Fixup::kindSetTargetAddress:
+                       f = fixup;
+                       do { 
+                               ++f;
+                       } while ( ! f->lastInCluster() );
+                       switch (f->kind ) {
+                               case ld::Fixup::kindStoreARM64Page21:
+                                       return !mustBeGOT;
+                               case ld::Fixup::kindStoreARM64GOTLoadPage21:
+                               case ld::Fixup::kindStoreARM64GOTLeaPage21:
+                               case ld::Fixup::kindStoreARM64TLVPLoadPage21:
+                               case ld::Fixup::kindStoreARM64TLVPLoadNowLeaPage21:
+                                       return true;
+                               default:
+                                       break;
+                       }
+                       break;
+               default:
+                       break;
+       }
+       return false;
+}
+
+static bool isPageOffsetKind(const ld::Fixup* fixup, bool mustBeGOT=false)
+{
+       if ( fixup == NULL )
+               return false;
+       const ld::Fixup* f;
+       switch ( fixup->kind ) {
+               case ld::Fixup::kindStoreTargetAddressARM64PageOff12:
+                       return !mustBeGOT;
+               case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12:
+               case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPageOff12:
+               case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPageOff12:
+               case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPageOff12:
+                       return true;
+               case ld::Fixup::kindSetTargetAddress:
+                       f = fixup;
+                       do { 
+                               ++f;
+                       } while ( ! f->lastInCluster() );
+                       switch (f->kind ) {
+                               case ld::Fixup::kindStoreARM64PageOff12:
+                                       return !mustBeGOT;
+                               case ld::Fixup::kindStoreARM64GOTLoadPageOff12:
+                               case ld::Fixup::kindStoreARM64GOTLeaPageOff12:
+                               case ld::Fixup::kindStoreARM64TLVPLoadPageOff12:
+                               case ld::Fixup::kindStoreARM64TLVPLoadNowLeaPageOff12:
+                                       return true;
+                               default:
+                                       break;
+                       }
+                       break;
+               default:
+                       break;
+       }
+       return false;
+}
+#endif // SUPPORT_ARCH_arm64
+
+
+#define LOH_ASSERT(cond) \
+       if ( !(cond) ) { \
+               warning("ignoring linker optimzation hint at %s+0x%X because " #cond, atom->name(), fit->offsetInAtom); \
+               break; \
+       } 
+
+void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::Atom* atom, uint8_t* buffer)
+{
+       //fprintf(stderr, "applyFixUps() on %s\n", atom->name());
+       int64_t accumulator = 0;
+       const ld::Atom* toTarget = NULL;        
+       const ld::Atom* fromTarget;
+       int64_t delta;
+       uint32_t instruction;
+       uint32_t newInstruction;
+       bool is_bl;
+       bool is_blx;
+       bool is_b;
+       bool thumbTarget = false;
+       std::map<uint32_t, const Fixup*> usedByHints;
+       for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+               uint8_t* fixUpLocation = &buffer[fit->offsetInAtom];
+               ld::Fixup::LOH_arm64 lohExtra;
+               switch ( (ld::Fixup::Kind)(fit->kind) ) { 
+                       case ld::Fixup::kindNone:
+                       case ld::Fixup::kindNoneFollowOn:
+                       case ld::Fixup::kindNoneGroupSubordinate:
+                       case ld::Fixup::kindNoneGroupSubordinateFDE:
+                       case ld::Fixup::kindNoneGroupSubordinateLSDA:
+                       case ld::Fixup::kindNoneGroupSubordinatePersonality:
+                               break;
+                       case ld::Fixup::kindSetTargetAddress:
+                               accumulator = addressOf(state, fit, &toTarget);                 
+                               thumbTarget = targetIsThumb(state, fit);
+                               if ( thumbTarget ) 
+                                       accumulator |= 1;
+                               if ( fit->contentAddendOnly || fit->contentDetlaToAddendOnly )
+                                       accumulator = 0;
+                               break;
+                       case ld::Fixup::kindSubtractTargetAddress:
+                               delta = addressOf(state, fit, &fromTarget);
+                               if ( ! fit->contentAddendOnly )
+                                       accumulator -= delta;
+                               break;
+                       case ld::Fixup::kindAddAddend:
+                               if ( ! fit->contentIgnoresAddend ) {
+                                       // <rdar://problem/8342028> ARM main executables main contain .long constants pointing
+                                       // into themselves such as jump tables.  These .long should not have thumb bit set
+                                       // even though the target is a thumb instruction. We can tell it is an interior pointer
+                                       // because we are processing an addend. 
+                                       if ( thumbTarget && (toTarget == atom) && ((int32_t)fit->u.addend > 0) ) {
+                                               accumulator &= (-2);
+                                               //warning("removing thumb bit from intra-atom pointer in %s %s+0x%0X", 
+                                               //              atom->section().sectionName(), atom->name(), fit->offsetInAtom);
+                                       }
+                                       accumulator += fit->u.addend;
+                               }
+                               break;
+                       case ld::Fixup::kindSubtractAddend:
+                               accumulator -= fit->u.addend;
+                               break;
+                       case ld::Fixup::kindSetTargetImageOffset:
+                               accumulator = addressOf(state, fit, &toTarget) - mhAddress;
+                               thumbTarget = targetIsThumb(state, fit);
+                               if ( thumbTarget ) 
+                                       accumulator |= 1;
+                               break;
+                       case ld::Fixup::kindSetTargetSectionOffset:
+                               accumulator = sectionOffsetOf(state, fit);
+                               break;
+                       case ld::Fixup::kindSetTargetTLVTemplateOffset:
+                               accumulator = tlvTemplateOffsetOf(state, fit);
+                               break;
+                       case ld::Fixup::kindStore8:
+                               *fixUpLocation += accumulator;
+                               break;
+                       case ld::Fixup::kindStoreLittleEndian16:
+                               set16LE(fixUpLocation, accumulator);
+                               break;
+                       case ld::Fixup::kindStoreLittleEndianLow24of32:
+                               set32LE(fixUpLocation, (get32LE(fixUpLocation) & 0xFF000000) | (accumulator & 0x00FFFFFF) );
+                               break;
+                       case ld::Fixup::kindStoreLittleEndian32:
+                               rangeCheckAbsolute32(accumulator, state, atom, fit);
+                               set32LE(fixUpLocation, accumulator);
+                               break;
+                       case ld::Fixup::kindStoreLittleEndian64:
+                               set64LE(fixUpLocation, accumulator);
+                               break;
+                       case ld::Fixup::kindStoreBigEndian16:
+                               set16BE(fixUpLocation, accumulator);
+                               break;
+                       case ld::Fixup::kindStoreBigEndianLow24of32:
+                               set32BE(fixUpLocation, (get32BE(fixUpLocation) & 0xFF000000) | (accumulator & 0x00FFFFFF) );
+                               break;
+                       case ld::Fixup::kindStoreBigEndian32:
+                               rangeCheckAbsolute32(accumulator, state, atom, fit);
+                               set32BE(fixUpLocation, accumulator);
+                               break;
+                       case ld::Fixup::kindStoreBigEndian64:
+                               set64BE(fixUpLocation, accumulator);
+                               break;
+                       case ld::Fixup::kindStoreX86PCRel8:
+                       case ld::Fixup::kindStoreX86BranchPCRel8:
+                               if ( fit->contentAddendOnly )
+                                       delta = accumulator;
+                               else
+                                       delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 1);
+                               rangeCheck8(delta, state, atom, fit);
+                               *fixUpLocation = delta;
+                               break;
+                       case ld::Fixup::kindStoreX86PCRel16:
+                               if ( fit->contentAddendOnly )
+                                       delta = accumulator;
+                               else
+                                       delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 2);
+                               rangeCheck16(delta, state, atom, fit);
+                               set16LE(fixUpLocation, delta);
+                               break;
+                       case ld::Fixup::kindStoreX86BranchPCRel32:
+                               if ( fit->contentAddendOnly )
+                                       delta = accumulator;
+                               else
+                                       delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 4);
+                               rangeCheckBranch32(delta, state, atom, fit);
+                               set32LE(fixUpLocation, delta);
+                               break;
+                       case ld::Fixup::kindStoreX86PCRel32GOTLoad:
+                       case ld::Fixup::kindStoreX86PCRel32GOT:
+                       case ld::Fixup::kindStoreX86PCRel32:
+                       case ld::Fixup::kindStoreX86PCRel32TLVLoad:
+                               if ( fit->contentAddendOnly )
+                                       delta = accumulator;
+                               else
+                                       delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 4);
+                               rangeCheckRIP32(delta, state, atom, fit);
+                               set32LE(fixUpLocation, delta);
+                               break;
+                       case ld::Fixup::kindStoreX86PCRel32_1:
+                               if ( fit->contentAddendOnly )
+                                       delta = accumulator - 1;
+                               else
+                                       delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 5);
+                               rangeCheckRIP32(delta, state, atom, fit);
+                               set32LE(fixUpLocation, delta);
+                               break;
+                       case ld::Fixup::kindStoreX86PCRel32_2:
+                               if ( fit->contentAddendOnly )
+                                       delta = accumulator - 2;
                                else
                                        delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 6);
                                rangeCheckRIP32(delta, state, atom, fit);
@@ -1092,41 +1502,6 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                }
                                set32LE(fixUpLocation, newInstruction);
                                break;
-                       case ld::Fixup::kindStorePPCBranch14:
-                               delta = accumulator - (atom->finalAddress() + fit->offsetInAtom);
-                               rangeCheckPPCBranch14(delta, state, atom, fit);
-                               instruction = get32BE(fixUpLocation);
-                               newInstruction = (instruction & 0xFFFF0003) | ((uint32_t)delta & 0x0000FFFC);
-                               set32BE(fixUpLocation, newInstruction);
-                               break;
-                       case ld::Fixup::kindStorePPCPicLow14:
-                       case ld::Fixup::kindStorePPCAbsLow14:
-                               instruction = get32BE(fixUpLocation);
-                               if ( (accumulator & 0x3) != 0 )
-                                       throwf("bad offset (0x%08X) for lo14 instruction pic-base fix-up", (uint32_t)accumulator);
-                               newInstruction = (instruction & 0xFFFF0003) | (accumulator & 0xFFFC);
-                               set32BE(fixUpLocation, newInstruction);
-                               break;
-                       case ld::Fixup::kindStorePPCAbsLow16:
-                       case ld::Fixup::kindStorePPCPicLow16:
-                               instruction = get32BE(fixUpLocation);
-                               newInstruction = (instruction & 0xFFFF0000) | (accumulator & 0xFFFF);
-                               set32BE(fixUpLocation, newInstruction);
-                               break;
-                       case ld::Fixup::kindStorePPCAbsHigh16AddLow:
-                       case ld::Fixup::kindStorePPCPicHigh16AddLow:
-                               instructionLowHalf = (accumulator >> 16) & 0xFFFF;
-                               if ( accumulator & 0x00008000 )
-                                       ++instructionLowHalf;
-                               instruction = get32BE(fixUpLocation);
-                               newInstruction = (instruction & 0xFFFF0000) | instructionLowHalf;
-                               set32BE(fixUpLocation, newInstruction);
-                               break;
-                       case ld::Fixup::kindStorePPCAbsHigh16:
-                               instruction = get32BE(fixUpLocation);
-                               newInstruction = (instruction & 0xFFFF0000) | ((accumulator >> 16) & 0xFFFF);
-                               set32BE(fixUpLocation, newInstruction);
-                               break;
                        case ld::Fixup::kindDtraceExtra:
                                break;
                        case ld::Fixup::kindStoreX86DtraceCallSiteNop:
@@ -1149,18 +1524,6 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                        fixUpLocation[3] = 0x90;                // 1-byte nop
                                }
                                break;
-                       case ld::Fixup::kindStorePPCDtraceCallSiteNop:
-                               if ( _options.outputKind() != Options::kObjectFile ) {
-                                       // change call site to a NOP
-                                       set32BE(fixUpLocation, 0x60000000);
-                               }
-                               break;
-                       case ld::Fixup::kindStorePPCDtraceIsEnableSiteClear:
-                               if ( _options.outputKind() != Options::kObjectFile ) {
-                                       // change call site to a li r3,0
-                                       set32BE(fixUpLocation, 0x38600000);
-                               }
-                               break;
                        case ld::Fixup::kindStoreARMDtraceCallSiteNop:
                                if ( _options.outputKind() != Options::kObjectFile ) {
                                        // change call site to a NOP
@@ -1185,12 +1548,43 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                        set32LE(fixUpLocation, 0x46C04040);
                                }
                                break;
+                       case ld::Fixup::kindStoreARM64DtraceCallSiteNop:
+                               if ( _options.outputKind() != Options::kObjectFile ) {
+                                       // change call site to a NOP
+                                       set32LE(fixUpLocation, 0xD503201F);
+                               }
+                               break;
+                       case ld::Fixup::kindStoreARM64DtraceIsEnableSiteClear:
+                               if ( _options.outputKind() != Options::kObjectFile ) {
+                                       // change call site to 'MOVZ X0,0'
+                                       set32LE(fixUpLocation, 0xD2800000);
+                               }
+                               break;
                        case ld::Fixup::kindLazyTarget:
+                       case ld::Fixup::kindIslandTarget:
                                break;
                        case ld::Fixup::kindSetLazyOffset:
                                assert(fit->binding == ld::Fixup::bindingDirectlyBound);
                                accumulator = this->lazyBindingInfoOffsetForLazyPointerAddress(fit->u.target->finalAddress());
                                break;
+                       case ld::Fixup::kindDataInCodeStartData:
+                       case ld::Fixup::kindDataInCodeStartJT8:
+                       case ld::Fixup::kindDataInCodeStartJT16:
+                       case ld::Fixup::kindDataInCodeStartJT32:
+                       case ld::Fixup::kindDataInCodeStartJTA32:
+                       case ld::Fixup::kindDataInCodeEnd:
+                               break;
+                       case ld::Fixup::kindLinkerOptimizationHint:
+                               // expand table of address/offsets used by hints
+                               lohExtra.addend = fit->u.addend;
+                               usedByHints[fit->offsetInAtom + (lohExtra.info.delta1 << 2)] = NULL;
+                               if ( lohExtra.info.count > 0 )
+                                       usedByHints[fit->offsetInAtom + (lohExtra.info.delta2 << 2)] = NULL;
+                               if ( lohExtra.info.count > 1 )
+                                       usedByHints[fit->offsetInAtom + (lohExtra.info.delta3 << 2)] = NULL;
+                               if ( lohExtra.info.count > 2 )
+                                       usedByHints[fit->offsetInAtom + (lohExtra.info.delta4 << 2)] = NULL;
+                               break;
                        case ld::Fixup::kindStoreTargetAddressLittleEndian32:
                                accumulator = addressOf(state, fit, &toTarget);
                                thumbTarget = targetIsThumb(state, fit);
@@ -1198,6 +1592,7 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                        accumulator |= 1;
                                if ( fit->contentAddendOnly )
                                        accumulator = 0;
+                               rangeCheckAbsolute32(accumulator, state, atom, fit);
                                set32LE(fixUpLocation, accumulator);
                                break;
                        case ld::Fixup::kindStoreTargetAddressLittleEndian64:
@@ -1274,6 +1669,22 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                        case ld::Fixup::kindStoreTargetAddressARMBranch24:
                                accumulator = addressOf(state, fit, &toTarget);
                                thumbTarget = targetIsThumb(state, fit);
+                               if ( toTarget->contentType() == ld::Atom::typeBranchIsland ) {
+                                       // Branching to island.  If ultimate target is in range, branch there directly.
+                                       for (ld::Fixup::iterator islandfit = toTarget->fixupsBegin(), end=toTarget->fixupsEnd(); islandfit != end; ++islandfit) {
+                                               if ( islandfit->kind == ld::Fixup::kindIslandTarget ) {
+                                                       const ld::Atom* islandTarget = NULL;
+                                                       uint64_t islandTargetAddress = addressOf(state, islandfit, &islandTarget);
+                                                       delta = islandTargetAddress - (atom->finalAddress() + fit->offsetInAtom + 4);
+                                                       if ( checkArmBranch24Displacement(delta) ) {
+                                                               toTarget = islandTarget;
+                                                               accumulator = islandTargetAddress;
+                                                               thumbTarget = targetIsThumb(state, islandfit);
+                                                       }
+                                                       break;
+                                               }
+                                       }
+                               }
                                if ( thumbTarget ) 
                                        accumulator |= 1;
                                if ( fit->contentDetlaToAddendOnly )
@@ -1284,20 +1695,28 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 8);
                                rangeCheckARMBranch24(delta, state, atom, fit);
                                instruction = get32LE(fixUpLocation);
-                               // Make sure we are calling arm with bl, thumb with blx                 
+                               // Make sure we are calling arm with bl, thumb with blx         
                                is_bl = ((instruction & 0xFF000000) == 0xEB000000);
                                is_blx = ((instruction & 0xFE000000) == 0xFA000000);
-                               if ( is_bl && thumbTarget ) {
-                                       uint32_t opcode = 0xFA000000;
+                               is_b = !is_blx && ((instruction & 0x0F000000) == 0x0A000000);
+                               if ( (is_bl | is_blx) && thumbTarget ) {
+                                       uint32_t opcode = 0xFA000000;  // force to be blx
                                        uint32_t disp = (uint32_t)(delta >> 2) & 0x00FFFFFF;
                                        uint32_t h_bit = (uint32_t)(delta << 23) & 0x01000000;
                                        newInstruction = opcode | h_bit | disp;
                                } 
-                               else if ( is_blx && !thumbTarget ) {
-                                       uint32_t opcode = 0xEB000000;
+                               else if ( (is_bl | is_blx) && !thumbTarget ) {
+                                       uint32_t opcode = 0xEB000000;  // force to be bl
                                        uint32_t disp = (uint32_t)(delta >> 2) & 0x00FFFFFF;
                                        newInstruction = opcode | disp;
                                } 
+                               else if ( is_b && thumbTarget ) {
+                                       if ( fit->contentDetlaToAddendOnly )
+                                               newInstruction = (instruction & 0xFF000000) | ((uint32_t)(delta >> 2) & 0x00FFFFFF);
+                                       else
+                                               throwf("no pc-rel bx arm instruction. Can't fix up branch to %s in %s",
+                                                               referenceTargetAtomName(state, fit), atom->name());
+                               } 
                                else if ( !is_bl && !is_blx && thumbTarget ) {
                                        throwf("don't know how to convert instruction %x referencing %s to thumb",
                                                 instruction, referenceTargetAtomName(state, fit));
@@ -1310,6 +1729,38 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                        case ld::Fixup::kindStoreTargetAddressThumbBranch22:
                                accumulator = addressOf(state, fit, &toTarget);
                                thumbTarget = targetIsThumb(state, fit);
+                               if ( toTarget->contentType() == ld::Atom::typeBranchIsland ) {
+                                       // branching to island, so see if ultimate target is in range 
+                                       // and if so branch to ultimate target instead.
+                                       for (ld::Fixup::iterator islandfit = toTarget->fixupsBegin(), end=toTarget->fixupsEnd(); islandfit != end; ++islandfit) {
+                                               if ( islandfit->kind == ld::Fixup::kindIslandTarget ) {
+                                                       const ld::Atom* islandTarget = NULL;
+                                                       uint64_t islandTargetAddress = addressOf(state, islandfit, &islandTarget);
+                                                       if ( !fit->contentDetlaToAddendOnly ) {
+                                                               if ( targetIsThumb(state, islandfit) ) {
+                                                                       // Thumb to thumb branch, we will be generating a bl instruction.
+                                                                       // Delta is always even, so mask out thumb bit in target.
+                                                                       islandTargetAddress &= -2ULL;
+                                                               }
+                                                               else {
+                                                                       // Target is not thumb, we will be generating a blx instruction
+                                                                       // Since blx cannot have the low bit set, set bit[1] of the target to
+                                                                       // bit[1] of the base address, so that the difference is a multiple of
+                                                                       // 4 bytes.
+                                                                       islandTargetAddress &= -3ULL;
+                                                                       islandTargetAddress |= ((atom->finalAddress() + fit->offsetInAtom ) & 2LL);
+                                                               }
+                                                       }
+                                                       delta = islandTargetAddress - (atom->finalAddress() + fit->offsetInAtom + 4);
+                                                       if ( checkThumbBranch22Displacement(delta) ) {
+                                                               toTarget = islandTarget;
+                                                               accumulator = islandTargetAddress;
+                                                               thumbTarget = targetIsThumb(state, islandfit);
+                                                       }
+                                                       break;
+                                               }
+                                       }
+                               }
                                if ( thumbTarget ) 
                                        accumulator |= 1;
                                if ( fit->contentDetlaToAddendOnly )
@@ -1320,18 +1771,30 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                is_bl = ((instruction & 0xD000F800) == 0xD000F000);
                                is_blx = ((instruction & 0xD000F800) == 0xC000F000);
                                is_b = ((instruction & 0xD000F800) == 0x9000F000);
-                               // If the target is not thumb, we will be generating a blx instruction
-                               // Since blx cannot have the low bit set, set bit[1] of the target to
-                               // bit[1] of the base address, so that the difference is a multiple of
-                               // 4 bytes.
-                               if ( !thumbTarget ) {
-                                 accumulator &= -3ULL;
-                                 accumulator |= ((atom->finalAddress() + fit->offsetInAtom ) & 2LL);
+                               if ( !fit->contentDetlaToAddendOnly ) {
+                                       if ( thumbTarget ) {
+                                               // Thumb to thumb branch, we will be generating a bl instruction.
+                                               // Delta is always even, so mask out thumb bit in target.
+                                               accumulator &= -2ULL;
+                                       }
+                                       else {
+                                               // Target is not thumb, we will be generating a blx instruction
+                                               // Since blx cannot have the low bit set, set bit[1] of the target to
+                                               // bit[1] of the base address, so that the difference is a multiple of
+                                               // 4 bytes.
+                                               accumulator &= -3ULL;
+                                               accumulator |= ((atom->finalAddress() + fit->offsetInAtom ) & 2LL);
+                                       }
                                }
                                // The pc added will be +4 from the pc
                                delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 4);
+                               // <rdar://problem/16652542> support bl in very large .o files
+                               if ( fit->contentDetlaToAddendOnly ) {
+                                       while ( delta < (-16777216LL) ) 
+                                               delta += 0x2000000;
+                               }
                                rangeCheckThumbBranch22(delta, state, atom, fit);
-                               if ( _options.preferSubArchitecture() && _options.subArchitecture() == CPU_SUBTYPE_ARM_V7 ) {
+                               if ( _options.preferSubArchitecture() && _options.archSupportsThumb2() ) {
                                        // The instruction is really two instructions:
                                        // The lower 16 bits are the first instruction, which contains the high
                                        //   11 bits of the displacement.
@@ -1357,12 +1820,13 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                                        instruction = 0xC000F000; // keep blx
                                        }
                                        else if ( is_b ) {
-                                               if ( !thumbTarget ) 
-                                                       throwf("don't know how to convert instruction %x referencing %s to arm",
-                                                                       instruction, referenceTargetAtomName(state, fit));
                                                instruction = 0x9000F000; // keep b
+                                               if ( !thumbTarget && !fit->contentDetlaToAddendOnly ) {
+                                                       throwf("armv7 has no pc-rel bx thumb instruction. Can't fix up branch to %s in %s",
+                                                                       referenceTargetAtomName(state, fit), atom->name());
+                                               }
                                        } 
-                                       else if ( is_b ) {
+                                       else {
                                                if ( !thumbTarget ) 
                                                        throwf("don't know how to convert branch instruction %x referencing %s to bx",
                                                                        instruction, referenceTargetAtomName(state, fit));
@@ -1371,8 +1835,8 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                        uint32_t nextDisp = (j1 << 13) | (j2 << 11) | imm11;
                                        uint32_t firstDisp = (s << 10) | imm10;
                                        newInstruction = instruction | (nextDisp << 16) | firstDisp;
-                                       //warning("s=%d, j1=%d, j2=%d, imm10=0x%0X, imm11=0x%0X, opcode=0x%08X, first=0x%04X, next=0x%04X, new=0x%08X, disp=0x%llX for %s to %s\n",
-                                       //      s, j1, j2, imm10, imm11, opcode, firstDisp, nextDisp, newInstruction, delta, inAtom->getDisplayName(), ref->getTarget().getDisplayName());
+                                       //warning("s=%d, j1=%d, j2=%d, imm10=0x%0X, imm11=0x%0X, instruction=0x%08X, first=0x%04X, next=0x%04X, new=0x%08X, disp=0x%llX for %s to %s\n",
+                                       //      s, j1, j2, imm10, imm11, instruction, firstDisp, nextDisp, newInstruction, delta, atom->name(), toTarget->name());
                                        set32LE(fixUpLocation, newInstruction);                         
                                }
                                else {
@@ -1389,10 +1853,13 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                        else if ( is_blx && thumbTarget ) {
                                                instruction = 0xF800F000;
                                        } 
-                                       else if ( !is_bl && !is_blx && !thumbTarget ) {
-                                         throwf("don't know how to convert instruction %x referencing %s to arm",
-                                                        instruction, referenceTargetAtomName(state, fit));
-                                       } 
+                                       else if ( is_b ) {
+                                               instruction = 0x9000F000; // keep b
+                                               if ( !thumbTarget && !fit->contentDetlaToAddendOnly ) {
+                                                       throwf("armv6 has no pc-rel bx thumb instruction. Can't fix up branch to %s in %s",
+                                                                       referenceTargetAtomName(state, fit), atom->name());
+                                               }
+                                       }
                                        else {
                                                instruction = instruction & 0xF800F800;
                                        }
@@ -1418,60 +1885,640 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                        set32LE(fixUpLocation, newInstruction);         
                                }
                                break;
-                       case ld::Fixup::kindStoreThumbLow16:
+                       case ld::Fixup::kindStoreThumbLow16:
+                               {
+                                       uint32_t imm4 = (accumulator & 0x0000F000) >> 12;
+                                       uint32_t i =    (accumulator & 0x00000800) >> 11;
+                                       uint32_t imm3 = (accumulator & 0x00000700) >> 8;
+                                       uint32_t imm8 =  accumulator & 0x000000FF;
+                                       instruction = get32LE(fixUpLocation);
+                                       newInstruction = (instruction & 0x8F00FBF0) | imm4 | (i << 10) | (imm3 << 28) | (imm8 << 16);
+                                       set32LE(fixUpLocation, newInstruction);         
+                               }
+                               break;
+                       case ld::Fixup::kindStoreThumbHigh16:
+                               {
+                                       uint32_t imm4 = (accumulator & 0xF0000000) >> 28;
+                                       uint32_t i =    (accumulator & 0x08000000) >> 27;
+                                       uint32_t imm3 = (accumulator & 0x07000000) >> 24;
+                                       uint32_t imm8 = (accumulator & 0x00FF0000) >> 16;
+                                       instruction = get32LE(fixUpLocation);
+                                       newInstruction = (instruction & 0x8F00FBF0) | imm4 | (i << 10) | (imm3 << 28) | (imm8 << 16);
+                                       set32LE(fixUpLocation, newInstruction);         
+                               }
+                               break;
+#if SUPPORT_ARCH_arm64
+                       case ld::Fixup::kindStoreTargetAddressARM64Branch26:
+                               accumulator = addressOf(state, fit, &toTarget);
+                               // fall into kindStoreARM64Branch26 case
+                       case ld::Fixup::kindStoreARM64Branch26:
+                               if ( fit->contentAddendOnly )
+                                       delta = accumulator;
+                               else
+                    delta = accumulator - (atom->finalAddress() + fit->offsetInAtom);
+                               rangeCheckARM64Branch26(delta, state, atom, fit);
+                               instruction = get32LE(fixUpLocation);
+                               newInstruction = (instruction & 0xFC000000) | ((uint32_t)(delta >> 2) & 0x03FFFFFF);
+                               set32LE(fixUpLocation, newInstruction);
+                               break;
+                       case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21:
+                       case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
+                       case ld::Fixup::kindStoreTargetAddressARM64Page21:
+                       case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPage21:
+                       case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPage21:
+                               accumulator = addressOf(state, fit, &toTarget);
+                               // fall into kindStoreARM64Branch26 case
+                       case ld::Fixup::kindStoreARM64GOTLeaPage21:
+                       case ld::Fixup::kindStoreARM64GOTLoadPage21:
+                       case ld::Fixup::kindStoreARM64TLVPLoadPage21:
+                       case ld::Fixup::kindStoreARM64TLVPLoadNowLeaPage21:
+                       case ld::Fixup::kindStoreARM64Page21:
+                               {
+                                       // the ADRP instruction adds the imm << 12 to the page that the pc is on
+                                       if ( fit->contentAddendOnly )
+                                               delta = 0;
+                                       else
+                                               delta = (accumulator & (-4096)) - ((atom->finalAddress() + fit->offsetInAtom) & (-4096));
+                                       rangeCheckARM64Page21(delta, state, atom, fit);
+                                       instruction = get32LE(fixUpLocation);
+                                       uint32_t immhi = (delta >> 9) & (0x00FFFFE0);
+                                       uint32_t immlo = (delta << 17) & (0x60000000);
+                                       newInstruction = (instruction & 0x9F00001F) | immlo | immhi;
+                                       set32LE(fixUpLocation, newInstruction);
+                               }
+                               break;
+                       case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12:
+                       case ld::Fixup::kindStoreTargetAddressARM64PageOff12:
+                       case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPageOff12:
+                               accumulator = addressOf(state, fit, &toTarget);
+                               // fall into kindAddressARM64PageOff12 case
+                       case ld::Fixup::kindStoreARM64TLVPLoadPageOff12:
+                       case ld::Fixup::kindStoreARM64GOTLoadPageOff12:
+                       case ld::Fixup::kindStoreARM64PageOff12:
+                               {
+                                       uint32_t offset = accumulator & 0x00000FFF;
+                                       instruction = get32LE(fixUpLocation);
+                                       // LDR/STR instruction have implicit scale factor, need to compensate for that
+                                       if ( instruction & 0x08000000 ) {
+                                               uint32_t implictShift = ((instruction >> 30) & 0x3);
+                                               switch ( implictShift ) {
+                                                       case 0:
+                                                               if ( (instruction & 0x04800000) == 0x04800000 ) {
+                                                                       // vector and byte LDR/STR have same "size" bits, need to check other bits to differenciate
+                                                                       implictShift = 4;
+                                                                       if ( (offset & 0xF) != 0 ) {
+                                                                                       throwf("128-bit LDR/STR not 16-byte aligned: from %s (0x%08llX) to %s (0x%08llX)", 
+                                                                                               atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fit), 
+                                                                                               addressOf(state, fit, &toTarget));
+                                                                       }
+                                                               }
+                                                               break;
+                                                       case 1:
+                                                               if ( (offset & 0x1) != 0 ) {
+                                                                               throwf("16-bit LDR/STR not 2-byte aligned: from %s (0x%08llX) to %s (0x%08llX)", 
+                                                                                       atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fit), 
+                                                                                       addressOf(state, fit, &toTarget));
+                                                               }
+                                                               break;
+                                                       case 2:
+                                                               if ( (offset & 0x3) != 0 ) {
+                                                                               throwf("32-bit LDR/STR not 4-byte aligned: from %s (0x%08llX) to %s (0x%08llX)", 
+                                                                                       atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fit), 
+                                                                                       addressOf(state, fit, &toTarget));
+                                                               }
+                                                               break;
+                                                       case 3:
+                                                               if ( (offset & 0x7) != 0 ) {
+                                                                               throwf("64-bit LDR/STR not 8-byte aligned: from %s (0x%08llX) to %s (0x%08llX)", 
+                                                                                       atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fit), 
+                                                                                       addressOf(state, fit, &toTarget));
+                                                               }
+                                                               break;
+                                               }
+                                               // compensate for implicit scale
+                                               offset >>= implictShift;
+                                       }
+                                       if ( fit->contentAddendOnly )
+                                               offset = 0;
+                                       uint32_t imm12 = offset << 10;
+                                       newInstruction = (instruction & 0xFFC003FF) | imm12;
+                                       set32LE(fixUpLocation, newInstruction);
+                               }
+                               break;
+                       case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPageOff12:
+                               accumulator = addressOf(state, fit, &toTarget);
+                               // fall into kindStoreARM64GOTLoadPage21 case
+                       case ld::Fixup::kindStoreARM64GOTLeaPageOff12:
                                {
-                                       uint32_t imm4 = (accumulator & 0x0000F000) >> 12;
-                                       uint32_t i =    (accumulator & 0x00000800) >> 11;
-                                       uint32_t imm3 = (accumulator & 0x00000700) >> 8;
-                                       uint32_t imm8 =  accumulator & 0x000000FF;
+                                       // GOT entry was optimized away, change LDR instruction to a ADD
                                        instruction = get32LE(fixUpLocation);
-                                       newInstruction = (instruction & 0x8F00FBF0) | imm4 | (i << 10) | (imm3 << 28) | (imm8 << 16);
-                                       set32LE(fixUpLocation, newInstruction);         
+                                       if ( (instruction & 0xFFC00000) != 0xF9400000 )
+                                               throwf("GOT load reloc does not point to a LDR instruction in %s", atom->name());
+                                       uint32_t offset = accumulator & 0x00000FFF;
+                                       uint32_t imm12 = offset << 10;
+                                       newInstruction = 0x91000000 | imm12 | (instruction & 0x000003FF);
+                                       set32LE(fixUpLocation, newInstruction);
                                }
                                break;
-                       case ld::Fixup::kindStoreThumbHigh16:
+                       case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPageOff12:
+                               accumulator = addressOf(state, fit, &toTarget);
+                               // fall into kindStoreARM64TLVPLeaPageOff12 case
+                       case ld::Fixup::kindStoreARM64TLVPLoadNowLeaPageOff12:
                                {
-                                       uint32_t imm4 = (accumulator & 0xF0000000) >> 28;
-                                       uint32_t i =    (accumulator & 0x08000000) >> 27;
-                                       uint32_t imm3 = (accumulator & 0x07000000) >> 24;
-                                       uint32_t imm8 = (accumulator & 0x00FF0000) >> 16;
+                                       // TLV thunk in same linkage unit, so LEA it directly, changing LDR instruction to a ADD
                                        instruction = get32LE(fixUpLocation);
-                                       newInstruction = (instruction & 0x8F00FBF0) | imm4 | (i << 10) | (imm3 << 28) | (imm8 << 16);
-                                       set32LE(fixUpLocation, newInstruction);         
+                                       if ( (instruction & 0xFFC00000) != 0xF9400000 )
+                                               throwf("TLV load reloc does not point to a LDR instruction in %s", atom->name());
+                                       uint32_t offset = accumulator & 0x00000FFF;
+                                       uint32_t imm12 = offset << 10;
+                                       newInstruction = 0x91000000 | imm12 | (instruction & 0x000003FF);
+                                       set32LE(fixUpLocation, newInstruction);
                                }
                                break;
-                       case ld::Fixup::kindStoreTargetAddressPPCBranch24:
-                               accumulator = addressOf(state, fit, &toTarget);
-                               if ( fit->contentDetlaToAddendOnly )
-                                       accumulator = 0;
-                               // fall into kindStorePPCBranch24 case
-                       case ld::Fixup::kindStorePPCBranch24:
-                               delta = accumulator - (atom->finalAddress() + fit->offsetInAtom);
-                               rangeCheckPPCBranch24(delta, state, atom, fit);
-                               instruction = get32BE(fixUpLocation);
-                               newInstruction = (instruction & 0xFC000003) | ((uint32_t)delta & 0x03FFFFFC);
-                               set32BE(fixUpLocation, newInstruction);
+                       case ld::Fixup::kindStoreARM64PointerToGOT:
+                               set64LE(fixUpLocation, accumulator);
+                               break;
+            case ld::Fixup::kindStoreARM64PCRelToGOT:
+                               if ( fit->contentAddendOnly )
+                                       delta = accumulator;
+                               else
+                                       delta = accumulator - (atom->finalAddress() + fit->offsetInAtom);
+                               set32LE(fixUpLocation, delta);
                                break;
+#endif
+               }
+       }
+       
+#if SUPPORT_ARCH_arm64
+       // after all fixups are done on atom, if there are potential optimizations, do those
+       if ( (usedByHints.size() != 0) && (_options.outputKind() != Options::kObjectFile) && !_options.ignoreOptimizationHints() ) {
+               // fill in second part of usedByHints map, so we can see the target of fixups that might be optimized
+               for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+                       switch ( fit->kind ) {
+                               case ld::Fixup::kindLinkerOptimizationHint:
+                               case ld::Fixup::kindNoneFollowOn:
+                               case ld::Fixup::kindNoneGroupSubordinate:
+                               case ld::Fixup::kindNoneGroupSubordinateFDE:
+                               case ld::Fixup::kindNoneGroupSubordinateLSDA:
+                               case ld::Fixup::kindNoneGroupSubordinatePersonality:
+                                       break;
+                               default:
+                                       if ( fit->firstInCluster() ) {
+                                               std::map<uint32_t, const Fixup*>::iterator pos = usedByHints.find(fit->offsetInAtom);
+                                               if ( pos != usedByHints.end() ) {
+                                                       assert(pos->second == NULL && "two fixups in same hint location");
+                                                       pos->second = fit;
+                                                       //fprintf(stderr, "setting %s usedByHints[0x%04X], kind = %d\n",  atom->name(), fit->offsetInAtom, fit->kind);
+                                               }
+                                       }
+                       }
+               }
+               
+               // apply hints pass 1
+               for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+                       if ( fit->kind != ld::Fixup::kindLinkerOptimizationHint ) 
+                               continue;
+                       InstructionInfo infoA;
+                       InstructionInfo infoB;
+                       InstructionInfo infoC;
+                       InstructionInfo infoD;
+                       LoadStoreInfo ldrInfoB, ldrInfoC;
+                       AddInfo addInfoB;
+                       AdrpInfo adrpInfoA;
+                       bool usableSegment;
+                       bool targetFourByteAligned;
+                       bool literalableSize, isADRP, isADD, isLDR, isSTR;
+                       //uint8_t loadSize, destReg;
+                       //uint32_t scaledOffset;
+                       //uint32_t imm12;
+                       ld::Fixup::LOH_arm64 alt;
+                       alt.addend = fit->u.addend;
+                       setInfo(state, atom, buffer, usedByHints, fit->offsetInAtom, (alt.info.delta1 << 2), &infoA);
+                       if ( alt.info.count > 0 ) 
+                               setInfo(state, atom, buffer, usedByHints, fit->offsetInAtom, (alt.info.delta2 << 2), &infoB);
+                       if ( alt.info.count > 1 )
+                               setInfo(state, atom, buffer, usedByHints, fit->offsetInAtom, (alt.info.delta3 << 2), &infoC);
+                       if ( alt.info.count > 2 )
+                               setInfo(state, atom, buffer, usedByHints, fit->offsetInAtom, (alt.info.delta4 << 2), &infoD);
+
+                       if ( _options.sharedRegionEligible() ) {
+                               if ( _options.sharedRegionEncodingV2() ) {
+                                       // In v2 format, all references might be move at dyld shared cache creation time
+                                       usableSegment = false;
+                               }
+                               else {
+                                       // In v1 format, only references to something in __TEXT segment could be optimized
+                                       usableSegment = (strcmp(atom->section().segmentName(), infoB.target->section().segmentName()) == 0);
+                               }
+                       }
+                       else {
+                               // main executables can optimize any reference
+                               usableSegment = true;
+                       }
+
+                       switch ( alt.info.kind ) {
+                               case LOH_ARM64_ADRP_ADRP:
+                                       // processed in pass 2 because some ADRP may have been removed
+                                       break;
+                               case LOH_ARM64_ADRP_LDR:
+                                       LOH_ASSERT(alt.info.count == 1);
+                                       LOH_ASSERT(isPageKind(infoA.fixup));
+                                       LOH_ASSERT(isPageOffsetKind(infoB.fixup));
+                                       LOH_ASSERT(infoA.target == infoB.target);
+                                       LOH_ASSERT(infoA.targetAddress == infoB.targetAddress);
+                                       isADRP = parseADRP(infoA.instruction, adrpInfoA);
+                                       LOH_ASSERT(isADRP);
+                                       isLDR = parseLoadOrStore(infoB.instruction, ldrInfoB);
+                                       // silently ignore LDRs transformed to ADD by TLV pass
+                                       if ( !isLDR && infoB.fixup->kind == ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPageOff12 )
+                                               break;
+                                       LOH_ASSERT(isLDR);
+                                       LOH_ASSERT(ldrInfoB.baseReg == adrpInfoA.destReg);
+                                       LOH_ASSERT(ldrInfoB.offset == (infoA.targetAddress & 0x00000FFF));
+                                       literalableSize = ( (ldrInfoB.size != 1) && (ldrInfoB.size != 2) );
+                                       targetFourByteAligned = ( (infoA.targetAddress & 0x3) == 0 );
+                                       if ( literalableSize && usableSegment && targetFourByteAligned && withinOneMeg(infoB.instructionAddress, infoA.targetAddress) ) {
+                                               set32LE(infoA.instructionContent, makeNOP());
+                                               set32LE(infoB.instructionContent, makeLDR_literal(ldrInfoB, infoA.targetAddress, infoB.instructionAddress));
+                                               if ( _options.verboseOptimizationHints() )
+                                                       fprintf(stderr, "adrp-ldr at 0x%08llX transformed to LDR literal, usableSegment=%d usableSegment\n", infoB.instructionAddress, usableSegment);
+                                       }
+                                       else {
+                                               if ( _options.verboseOptimizationHints() )
+                                                       fprintf(stderr, "adrp-ldr at 0x%08llX not transformed, isLDR=%d, literalableSize=%d, inRange=%d, usableSegment=%d, scaledOffset=%d\n", 
+                                                               infoB.instructionAddress, isLDR, literalableSize, withinOneMeg(infoB.instructionAddress, infoA.targetAddress), usableSegment, ldrInfoB.offset);
+                                       }
+                                       break;
+                               case LOH_ARM64_ADRP_ADD_LDR:
+                                       LOH_ASSERT(alt.info.count == 2);
+                                       LOH_ASSERT(isPageKind(infoA.fixup));
+                                       LOH_ASSERT(isPageOffsetKind(infoB.fixup));
+                                       LOH_ASSERT(infoC.fixup == NULL);
+                                       LOH_ASSERT(infoA.target == infoB.target);
+                                       LOH_ASSERT(infoA.targetAddress == infoB.targetAddress);
+                                       isADRP = parseADRP(infoA.instruction, adrpInfoA);
+                                       LOH_ASSERT(isADRP);
+                                       isADD = parseADD(infoB.instruction, addInfoB);
+                                       LOH_ASSERT(isADD);
+                                       LOH_ASSERT(adrpInfoA.destReg == addInfoB.srcReg);
+                                       isLDR = parseLoadOrStore(infoC.instruction, ldrInfoC);
+                                       LOH_ASSERT(isLDR);
+                                       LOH_ASSERT(addInfoB.destReg == ldrInfoC.baseReg);
+                                       targetFourByteAligned = ( ((infoB.targetAddress+ldrInfoC.offset) & 0x3) == 0 );
+                                       literalableSize  = ( (ldrInfoC.size != 1) && (ldrInfoC.size != 2) );
+                                       if ( literalableSize && usableSegment && targetFourByteAligned && withinOneMeg(infoC.instructionAddress, infoA.targetAddress+ldrInfoC.offset) ) {
+                                               // can do T1 transformation to LDR literal
+                                               set32LE(infoA.instructionContent, makeNOP());
+                                               set32LE(infoB.instructionContent, makeNOP());
+                                               set32LE(infoC.instructionContent, makeLDR_literal(ldrInfoC, infoA.targetAddress+ldrInfoC.offset, infoC.instructionAddress));
+                                               if ( _options.verboseOptimizationHints() ) {
+                                                       fprintf(stderr, "adrp-add-ldr at 0x%08llX T1 transformed to LDR literal\n", infoC.instructionAddress);
+                                               }
+                                       }
+                                       else if ( usableSegment && withinOneMeg(infoA.instructionAddress, infoA.targetAddress+ldrInfoC.offset) ) {
+                                               // can to T4 transformation and turn ADRP/ADD into ADR
+                                               set32LE(infoA.instructionContent, makeADR(ldrInfoC.baseReg, infoA.targetAddress+ldrInfoC.offset, infoA.instructionAddress));
+                                               set32LE(infoB.instructionContent, makeNOP());   
+                                               ldrInfoC.offset = 0; // offset is now in ADR instead of ADD or LDR
+                                               set32LE(infoC.instructionContent, makeLoadOrStore(ldrInfoC));
+                                               set32LE(infoC.instructionContent, infoC.instruction & 0xFFC003FF);      
+                                               if ( _options.verboseOptimizationHints() )
+                                                       fprintf(stderr, "adrp-add-ldr at 0x%08llX T4 transformed to ADR/LDR\n", infoB.instructionAddress);                                              
+                                       }
+                                       else if ( ((infoB.targetAddress % ldrInfoC.size) == 0) && (ldrInfoC.offset == 0) ) {
+                                               // can do T2 transformation by merging ADD into LD
+                                               // Leave ADRP as-is
+                                               set32LE(infoB.instructionContent, makeNOP());   
+                                               ldrInfoC.offset += addInfoB.addend;
+                                               set32LE(infoC.instructionContent, makeLoadOrStore(ldrInfoC));
+                                               if ( _options.verboseOptimizationHints() )
+                                                       fprintf(stderr, "adrp-add-ldr at 0x%08llX T2 transformed to ADRP/LDR \n", infoC.instructionAddress);
+                                       }
+                                       else {
+                                               if ( _options.verboseOptimizationHints() )
+                                                       fprintf(stderr, "adrp-add-ldr at 0x%08llX could not be transformed, loadSize=%d, literalableSize=%d, inRange=%d, usableSegment=%d, targetFourByteAligned=%d, imm12=%d\n", 
+                                                                       infoC.instructionAddress, ldrInfoC.size, literalableSize, withinOneMeg(infoC.instructionAddress, infoA.targetAddress+ldrInfoC.offset), usableSegment, targetFourByteAligned, ldrInfoC.offset);
+                                       }
+                                       break;
+                               case LOH_ARM64_ADRP_ADD:
+                                       LOH_ASSERT(alt.info.count == 1);
+                                       LOH_ASSERT(isPageKind(infoA.fixup));
+                                       LOH_ASSERT(isPageOffsetKind(infoB.fixup));
+                                       LOH_ASSERT(infoA.target == infoB.target);
+                                       LOH_ASSERT(infoA.targetAddress == infoB.targetAddress);
+                                       isADRP = parseADRP(infoA.instruction, adrpInfoA);
+                                       LOH_ASSERT(isADRP);
+                                       isADD = parseADD(infoB.instruction, addInfoB);
+                                       LOH_ASSERT(isADD);
+                                       LOH_ASSERT(adrpInfoA.destReg == addInfoB.srcReg);
+                                       if ( usableSegment && withinOneMeg(infoA.targetAddress, infoA.instructionAddress) ) {
+                                               // can do T4 transformation and use ADR 
+                                               set32LE(infoA.instructionContent, makeADR(addInfoB.destReg, infoA.targetAddress, infoA.instructionAddress));
+                                               set32LE(infoB.instructionContent, makeNOP());   
+                                               if ( _options.verboseOptimizationHints() )
+                                                       fprintf(stderr, "adrp-add at 0x%08llX transformed to ADR\n", infoB.instructionAddress);
+                                       }
+                                       else {
+                                               if ( _options.verboseOptimizationHints() )
+                                                       fprintf(stderr, "adrp-add at 0x%08llX not transformed, isAdd=%d, inRange=%d, usableSegment=%d\n", 
+                                                               infoB.instructionAddress, isADD, withinOneMeg(infoA.targetAddress, infoA.instructionAddress), usableSegment);
+                                       }
+                                       break;
+                               case LOH_ARM64_ADRP_LDR_GOT_LDR:
+                                       LOH_ASSERT(alt.info.count == 2);
+                                       LOH_ASSERT(isPageKind(infoA.fixup, true));
+                                       LOH_ASSERT(isPageOffsetKind(infoB.fixup, true));
+                                       LOH_ASSERT(infoC.fixup == NULL);
+                                       LOH_ASSERT(infoA.target == infoB.target);
+                                       LOH_ASSERT(infoA.targetAddress == infoB.targetAddress);
+                                       isADRP = parseADRP(infoA.instruction, adrpInfoA);
+                                       LOH_ASSERT(isADRP);
+                                       isLDR = parseLoadOrStore(infoC.instruction, ldrInfoC);
+                                       LOH_ASSERT(isLDR);
+                                       LOH_ASSERT(ldrInfoC.offset == 0);
+                                       isADD = parseADD(infoB.instruction, addInfoB);
+                                       isLDR = parseLoadOrStore(infoB.instruction, ldrInfoB);
+                                       if ( isLDR ) {
+                                               // target of GOT is external
+                                               LOH_ASSERT(ldrInfoB.size == 8);
+                                               LOH_ASSERT(!ldrInfoB.isFloat);
+                                               LOH_ASSERT(ldrInfoC.baseReg == ldrInfoB.reg);
+                                               //fprintf(stderr, "infoA.target=%p, %s, infoA.targetAddress=0x%08llX\n", infoA.target, infoA.target->name(), infoA.targetAddress);
+                                               targetFourByteAligned = ( ((infoA.targetAddress) & 0x3) == 0 );
+                                               if ( usableSegment && targetFourByteAligned && withinOneMeg(infoB.instructionAddress, infoA.targetAddress) ) {
+                                                       // can do T5 transform
+                                                       set32LE(infoA.instructionContent, makeNOP());
+                                                       set32LE(infoB.instructionContent, makeLDR_literal(ldrInfoB, infoA.targetAddress, infoB.instructionAddress));
+                                                       if ( _options.verboseOptimizationHints() ) {
+                                                               fprintf(stderr, "adrp-ldr-got-ldr at 0x%08llX T5 transformed to LDR literal of GOT plus LDR\n", infoC.instructionAddress);
+                                                       }
+                                               }
+                                               else {
+                                                       if ( _options.verboseOptimizationHints() ) 
+                                                               fprintf(stderr, "adrp-ldr-got-ldr at 0x%08llX no optimization done\n", infoC.instructionAddress);
+                                               }
+                                       }
+                                       else if ( isADD ) {
+                                               // target of GOT is in same linkage unit and B instruction was changed to ADD to compute LEA of target
+                                               LOH_ASSERT(addInfoB.srcReg == adrpInfoA.destReg);
+                                               LOH_ASSERT(addInfoB.destReg == ldrInfoC.baseReg);
+                                               targetFourByteAligned = ( ((infoA.targetAddress) & 0x3) == 0 );
+                                               literalableSize  = ( (ldrInfoC.size != 1) && (ldrInfoC.size != 2) );
+                                               if ( usableSegment && literalableSize && targetFourByteAligned && withinOneMeg(infoC.instructionAddress, infoA.targetAddress) ) {
+                                                       // can do T1 transform
+                                                       set32LE(infoA.instructionContent, makeNOP());   
+                                                       set32LE(infoB.instructionContent, makeNOP());   
+                                                       set32LE(infoC.instructionContent, makeLDR_literal(ldrInfoC, infoA.targetAddress, infoC.instructionAddress));
+                                                       if ( _options.verboseOptimizationHints() ) 
+                                                               fprintf(stderr, "adrp-ldr-got-ldr at 0x%08llX T1 transformed to LDR literal\n", infoC.instructionAddress);
+                                               }
+                                               else if ( usableSegment && withinOneMeg(infoA.instructionAddress, infoA.targetAddress) ) {
+                                                       // can do T4 transform
+                                                       set32LE(infoA.instructionContent, makeADR(ldrInfoC.baseReg, infoA.targetAddress, infoA.instructionAddress));
+                                                       set32LE(infoB.instructionContent, makeNOP());   
+                                                       set32LE(infoC.instructionContent, makeLoadOrStore(ldrInfoC));
+                                                       if ( _options.verboseOptimizationHints() ) {
+                                                               fprintf(stderr, "adrp-ldr-got-ldr at 0x%08llX T4 transformed to ADR/LDR\n", infoC.instructionAddress);
+                                                       }
+                                               }
+                                               else if ( (infoA.targetAddress % ldrInfoC.size) == 0 ) {
+                                                       // can do T2 transform
+                                                       set32LE(infoB.instructionContent, makeNOP());
+                                                       ldrInfoC.baseReg = adrpInfoA.destReg;
+                                                       ldrInfoC.offset = addInfoB.addend;
+                                                       set32LE(infoC.instructionContent, makeLoadOrStore(ldrInfoC));
+                                                       if ( _options.verboseOptimizationHints() ) {
+                                                               fprintf(stderr, "adrp-ldr-got-ldr at 0x%08llX T4 transformed to ADRP/NOP/LDR\n", infoC.instructionAddress);
+                                                       }
+                                               }
+                                               else {
+                                                       // T3 transform already done by ld::passes:got:doPass()
+                                                       if ( _options.verboseOptimizationHints() ) {
+                                                               fprintf(stderr, "adrp-ldr-got-ldr at 0x%08llX T3 transformed to ADRP/ADD/LDR\n", infoC.instructionAddress);
+                                                       }
+                                               }
+                                       }
+                                       else {
+                                               if ( _options.verboseOptimizationHints() )                                                      
+                                                       fprintf(stderr, "adrp-ldr-got-ldr at 0x%08llX not ADD or LDR\n", infoC.instructionAddress);
+                                       }
+                                       break;
+                               case LOH_ARM64_ADRP_ADD_STR:
+                                       LOH_ASSERT(alt.info.count == 2);
+                                       LOH_ASSERT(isPageKind(infoA.fixup));
+                                       LOH_ASSERT(isPageOffsetKind(infoB.fixup));
+                                       LOH_ASSERT(infoC.fixup == NULL);
+                                       LOH_ASSERT(infoA.target == infoB.target);
+                                       LOH_ASSERT(infoA.targetAddress == infoB.targetAddress);
+                                       isADRP = parseADRP(infoA.instruction, adrpInfoA);
+                                       LOH_ASSERT(isADRP);
+                                       isADD = parseADD(infoB.instruction, addInfoB);
+                                       LOH_ASSERT(isADD);
+                                       LOH_ASSERT(adrpInfoA.destReg == addInfoB.srcReg);
+                                       isSTR = (parseLoadOrStore(infoC.instruction, ldrInfoC) && ldrInfoC.isStore);
+                                       LOH_ASSERT(isSTR);
+                                       LOH_ASSERT(addInfoB.destReg == ldrInfoC.baseReg);
+                                       if ( usableSegment && withinOneMeg(infoA.instructionAddress, infoA.targetAddress+ldrInfoC.offset) ) {
+                                               // can to T4 transformation and turn ADRP/ADD into ADR
+                                               set32LE(infoA.instructionContent, makeADR(ldrInfoC.baseReg, infoA.targetAddress+ldrInfoC.offset, infoA.instructionAddress));
+                                               set32LE(infoB.instructionContent, makeNOP());   
+                                               ldrInfoC.offset = 0; // offset is now in ADR instead of ADD or LDR
+                                               set32LE(infoC.instructionContent, makeLoadOrStore(ldrInfoC));
+                                               set32LE(infoC.instructionContent, infoC.instruction & 0xFFC003FF);      
+                                               if ( _options.verboseOptimizationHints() )
+                                                       fprintf(stderr, "adrp-add-str at 0x%08llX T4 transformed to ADR/STR\n", infoB.instructionAddress);                                              
+                                       }
+                                       else if ( ((infoB.targetAddress % ldrInfoC.size) == 0) && (ldrInfoC.offset == 0) ) {
+                                               // can do T2 transformation by merging ADD into STR
+                                               // Leave ADRP as-is
+                                               set32LE(infoB.instructionContent, makeNOP());   
+                                               ldrInfoC.offset += addInfoB.addend;
+                                               set32LE(infoC.instructionContent, makeLoadOrStore(ldrInfoC));
+                                               if ( _options.verboseOptimizationHints() )
+                                                       fprintf(stderr, "adrp-add-str at 0x%08llX T2 transformed to ADRP/STR \n", infoC.instructionAddress);
+                                       }
+                                       else {
+                                               if ( _options.verboseOptimizationHints() )
+                                                       fprintf(stderr, "adrp-add-str at 0x%08llX could not be transformed, loadSize=%d, inRange=%d, usableSegment=%d, imm12=%d\n", 
+                                                                       infoC.instructionAddress, ldrInfoC.size, withinOneMeg(infoC.instructionAddress, infoA.targetAddress+ldrInfoC.offset), usableSegment, ldrInfoC.offset);
+                                       }
+                                       break;
+                               case LOH_ARM64_ADRP_LDR_GOT_STR:
+                                       LOH_ASSERT(alt.info.count == 2);
+                                       LOH_ASSERT(isPageKind(infoA.fixup, true));
+                                       LOH_ASSERT(isPageOffsetKind(infoB.fixup, true));
+                                       LOH_ASSERT(infoC.fixup == NULL);
+                                       LOH_ASSERT(infoA.target == infoB.target);
+                                       LOH_ASSERT(infoA.targetAddress == infoB.targetAddress);
+                                       isADRP = parseADRP(infoA.instruction, adrpInfoA);
+                                       LOH_ASSERT(isADRP);
+                                       isSTR = (parseLoadOrStore(infoC.instruction, ldrInfoC) && ldrInfoC.isStore);
+                                       LOH_ASSERT(isSTR);
+                                       LOH_ASSERT(ldrInfoC.offset == 0);
+                                       isADD = parseADD(infoB.instruction, addInfoB);
+                                       isLDR = parseLoadOrStore(infoB.instruction, ldrInfoB);
+                                       if ( isLDR ) {
+                                               // target of GOT is external
+                                               LOH_ASSERT(ldrInfoB.size == 8);
+                                               LOH_ASSERT(!ldrInfoB.isFloat);
+                                               LOH_ASSERT(ldrInfoC.baseReg == ldrInfoB.reg);
+                                               targetFourByteAligned = ( ((infoA.targetAddress) & 0x3) == 0 );
+                                               if ( usableSegment && targetFourByteAligned && withinOneMeg(infoB.instructionAddress, infoA.targetAddress) ) {
+                                                       // can do T5 transform
+                                                       set32LE(infoA.instructionContent, makeNOP());
+                                                       set32LE(infoB.instructionContent, makeLDR_literal(ldrInfoB, infoA.targetAddress, infoB.instructionAddress));
+                                                       if ( _options.verboseOptimizationHints() ) {
+                                                               fprintf(stderr, "adrp-ldr-got-str at 0x%08llX T5 transformed to LDR literal of GOT plus STR\n", infoC.instructionAddress);
+                                                       }
+                                               }
+                                               else {
+                                                       if ( _options.verboseOptimizationHints() ) 
+                                                               fprintf(stderr, "adrp-ldr-got-str at 0x%08llX no optimization done\n", infoC.instructionAddress);
+                                               }
+                                       }
+                                       else if ( isADD ) {
+                                               // target of GOT is in same linkage unit and B instruction was changed to ADD to compute LEA of target
+                                               LOH_ASSERT(addInfoB.srcReg == adrpInfoA.destReg);
+                                               LOH_ASSERT(addInfoB.destReg == ldrInfoC.baseReg);
+                                               targetFourByteAligned = ( ((infoA.targetAddress) & 0x3) == 0 );
+                                               literalableSize  = ( (ldrInfoC.size != 1) && (ldrInfoC.size != 2) );
+                                               if ( usableSegment && withinOneMeg(infoA.instructionAddress, infoA.targetAddress) ) {
+                                                       // can do T4 transform
+                                                       set32LE(infoA.instructionContent, makeADR(ldrInfoC.baseReg, infoA.targetAddress, infoA.instructionAddress));
+                                                       set32LE(infoB.instructionContent, makeNOP());   
+                                                       set32LE(infoC.instructionContent, makeLoadOrStore(ldrInfoC));
+                                                       if ( _options.verboseOptimizationHints() ) {
+                                                               fprintf(stderr, "adrp-ldr-got-str at 0x%08llX T4 transformed to ADR/STR\n", infoC.instructionAddress);
+                                                       }
+                                               }
+                                               else if ( ((infoA.targetAddress % ldrInfoC.size) == 0) && (ldrInfoC.offset == 0) ) {
+                                                       // can do T2 transform
+                                                       set32LE(infoB.instructionContent, makeNOP());
+                                                       ldrInfoC.baseReg = adrpInfoA.destReg;
+                                                       ldrInfoC.offset = addInfoB.addend;
+                                                       set32LE(infoC.instructionContent, makeLoadOrStore(ldrInfoC));
+                                                       if ( _options.verboseOptimizationHints() ) {
+                                                               fprintf(stderr, "adrp-ldr-got-str at 0x%08llX T4 transformed to ADRP/NOP/STR\n", infoC.instructionAddress);
+                                                       }
+                                               }
+                                               else {
+                                                       // T3 transform already done by ld::passes:got:doPass()
+                                                       if ( _options.verboseOptimizationHints() ) {
+                                                               fprintf(stderr, "adrp-ldr-got-str at 0x%08llX T3 transformed to ADRP/ADD/STR\n", infoC.instructionAddress);
+                                                       }
+                                               }
+                                       }
+                                       else {
+                                               if ( _options.verboseOptimizationHints() )                                                      
+                                                       fprintf(stderr, "adrp-ldr-got-str at 0x%08llX not ADD or LDR\n", infoC.instructionAddress);
+                                       }
+                                       break;
+                               case LOH_ARM64_ADRP_LDR_GOT:
+                                       LOH_ASSERT(alt.info.count == 1);
+                                       LOH_ASSERT(isPageKind(infoA.fixup, true));
+                                       LOH_ASSERT(isPageOffsetKind(infoB.fixup, true));
+                                       LOH_ASSERT(infoA.target == infoB.target);
+                                       LOH_ASSERT(infoA.targetAddress == infoB.targetAddress);
+                                       isADRP = parseADRP(infoA.instruction, adrpInfoA);
+                                       isADD = parseADD(infoB.instruction, addInfoB);
+                                       isLDR = parseLoadOrStore(infoB.instruction, ldrInfoB);
+                                       if ( isADRP ) {
+                                               if ( isLDR ) {
+                                                       if ( usableSegment && withinOneMeg(infoB.instructionAddress, infoA.targetAddress) ) {
+                                                               // can do T5 transform (LDR literal load of GOT)
+                                                               set32LE(infoA.instructionContent, makeNOP());
+                                                               set32LE(infoB.instructionContent, makeLDR_literal(ldrInfoB, infoA.targetAddress, infoB.instructionAddress));
+                                                               if ( _options.verboseOptimizationHints() ) {
+                                                                       fprintf(stderr, "adrp-ldr-got at 0x%08llX T5 transformed to NOP/LDR\n", infoC.instructionAddress);
+                                                               }
+                                                       }
+                                               }
+                                               else if ( isADD ) {
+                                                       if ( usableSegment && withinOneMeg(infoA.instructionAddress, infoA.targetAddress) ) {
+                                                               // can do T4 transform (ADR to compute local address)
+                                                               set32LE(infoA.instructionContent, makeADR(addInfoB.destReg, infoA.targetAddress, infoA.instructionAddress));
+                                                               set32LE(infoB.instructionContent, makeNOP());
+                                                               if ( _options.verboseOptimizationHints() ) {
+                                                                       fprintf(stderr, "adrp-ldr-got at 0x%08llX T4 transformed to ADR/STR\n", infoC.instructionAddress);
+                                                               }
+                                                       }
+                                               }
+                                               else {
+                                                       if ( _options.verboseOptimizationHints() )
+                                                               fprintf(stderr, "adrp-ldr-got at 0x%08llX not LDR or ADD\n", infoB.instructionAddress);
+                                               }
+                                       }
+                                       else {
+                                               if ( _options.verboseOptimizationHints() )
+                                                       fprintf(stderr, "adrp-ldr-got at 0x%08llX not ADRP\n", infoA.instructionAddress);
+                                       }
+                                       break;
+                               default:
+                                               if ( _options.verboseOptimizationHints() )                                                      
+                                                       fprintf(stderr, "unknown hint kind %d alt.info.kind at 0x%08llX\n", alt.info.kind, infoA.instructionAddress);
+                                       break;
+                       }
+               }
+               // apply hints pass 2
+               for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+                       if ( fit->kind != ld::Fixup::kindLinkerOptimizationHint ) 
+                               continue;
+                       InstructionInfo infoA;
+                       InstructionInfo infoB;
+                       ld::Fixup::LOH_arm64 alt;
+                       alt.addend = fit->u.addend;
+                       setInfo(state, atom, buffer, usedByHints, fit->offsetInAtom, (alt.info.delta1 << 2), &infoA);
+                       if ( alt.info.count > 0 ) 
+                               setInfo(state, atom, buffer, usedByHints, fit->offsetInAtom, (alt.info.delta2 << 2), &infoB);
+
+                       switch ( alt.info.kind ) {
+                               case LOH_ARM64_ADRP_ADRP:
+                                       LOH_ASSERT(isPageKind(infoA.fixup));
+                                       LOH_ASSERT(isPageKind(infoB.fixup));
+                                       if ( (infoA.instruction & 0x9F000000) != 0x90000000 ) {
+                                               if ( _options.verboseOptimizationHints() )
+                                                       fprintf(stderr, "may-reused-adrp at 0x%08llX no longer an ADRP, now 0x%08X\n", infoA.instructionAddress, infoA.instruction);
+                                               sAdrpNA++;
+                                               break;
+                                       }
+                                       if ( (infoB.instruction & 0x9F000000) != 0x90000000 ) {
+                                               if ( _options.verboseOptimizationHints() )
+                                                       fprintf(stderr, "may-reused-adrp at 0x%08llX no longer an ADRP, now 0x%08X\n", infoB.instructionAddress, infoA.instruction);
+                                               sAdrpNA++;
+                                               break;
+                                       }
+                                       if ( (infoA.targetAddress & (-4096)) == (infoB.targetAddress & (-4096)) ) {
+                                               set32LE(infoB.instructionContent, 0xD503201F);
+                                               sAdrpNoped++;
+                                       }
+                                       else {
+                                               sAdrpNotNoped++;
+                                       }
+                                       break;
+                       }                               
                }
        }
+#endif // SUPPORT_ARCH_arm64
+
 }
 
-void OutputFile::copyNoOps(uint8_t* from, uint8_t* to)
+void OutputFile::copyNoOps(uint8_t* from, uint8_t* to, bool thumb)
 {
        switch ( _options.architecture() ) {
-               case CPU_TYPE_POWERPC:
-                       for (uint8_t* p=from; p < to; p += 4)
-                               OSWriteBigInt32((uint32_t*)p, 0, 0x60000000);
-                       break;
                case CPU_TYPE_I386:
                case CPU_TYPE_X86_64:
                        for (uint8_t* p=from; p < to; ++p)
                                *p = 0x90;
                        break;
                case CPU_TYPE_ARM:
-                       // fixme: need thumb nop?
-                       for (uint8_t* p=from; p < to; p += 4)
-                               OSWriteBigInt32((uint32_t*)p, 0, 0xe1a00000);
+                       if ( thumb ) {
+                               for (uint8_t* p=from; p < to; p += 2)
+                                       OSWriteLittleInt16((uint16_t*)p, 0, 0x46c0);
+                       }
+                       else {
+                               for (uint8_t* p=from; p < to; p += 4)
+                                       OSWriteLittleInt32((uint32_t*)p, 0, 0xe1a00000);
+                       }
                        break;
                default:
                        for (uint8_t* p=from; p < to; ++p)
@@ -1513,35 +2560,8 @@ bool OutputFile::hasZeroForFileOffset(const ld::Section* sect)
        return false;
 }
 
-
-void OutputFile::writeOutputFile(ld::Internal& state)
+void OutputFile::writeAtoms(ld::Internal& state, uint8_t* wholeBuffer)
 {
-       // for UNIX conformance, error if file exists and is not writable
-       if ( (access(_options.outputFilePath(), F_OK) == 0) && (access(_options.outputFilePath(), W_OK) == -1) )
-               throwf("can't write output file: %s", _options.outputFilePath());
-
-       int permissions = 0777;
-       if ( _options.outputKind() == Options::kObjectFile )
-               permissions = 0666;
-       // Calling unlink first assures the file is gone so that open creates it with correct permissions
-       // It also handles the case where __options.outputFilePath() file is not writable but its directory is
-       // And it means we don't have to truncate the file when done writing (in case new is smaller than old)
-       // Lastly, only delete existing file if it is a normal file (e.g. not /dev/null).
-       struct stat stat_buf;
-       if ( (stat(_options.outputFilePath(), &stat_buf) != -1) && (stat_buf.st_mode & S_IFREG) )
-               (void)unlink(_options.outputFilePath());
-
-       // try to allocate buffer for entire output file content
-       uint8_t* wholeBuffer = (uint8_t*)calloc(_fileSize, 1);
-       if ( wholeBuffer == NULL )
-               throwf("can't create buffer of %llu bytes for output", _fileSize);
-       
-       if ( _options.UUIDMode() == Options::kUUIDRandom ) {
-               uint8_t bits[16];
-               ::uuid_generate_random(bits);
-               _headersAndLoadCommandAtom->setUUID(bits);
-       }
-
        // have each atom write itself
        uint64_t fileOffsetOfEndOfLastAtom = 0;
        uint64_t mhAddress = 0;
@@ -1555,6 +2575,7 @@ void OutputFile::writeOutputFile(ld::Internal& state)
                const bool sectionUsesNops = (sect->type() == ld::Section::typeCode);
                //fprintf(stderr, "file offset=0x%08llX, section %s\n", sect->fileOffset, sect->sectionName());
                std::vector<const ld::Atom*>& atoms = sect->atoms;
+               bool lastAtomWasThumb = false;
                for (std::vector<const ld::Atom*>::iterator ait = atoms.begin(); ait != atoms.end(); ++ait) {
                        const ld::Atom* atom = *ait;
                        if ( atom->definition() == ld::Atom::definitionProxy )
@@ -1563,7 +2584,7 @@ void OutputFile::writeOutputFile(ld::Internal& state)
                                uint64_t fileOffset = atom->finalAddress() - sect->address + sect->fileOffset;
                                // check for alignment padding between atoms
                                if ( (fileOffset != fileOffsetOfEndOfLastAtom) && lastAtomUsesNoOps ) {
-                                       this->copyNoOps(&wholeBuffer[fileOffsetOfEndOfLastAtom], &wholeBuffer[fileOffset]);
+                                       this->copyNoOps(&wholeBuffer[fileOffsetOfEndOfLastAtom], &wholeBuffer[fileOffset], lastAtomWasThumb);
                                }
                                // copy atom content
                                atom->copyRawContent(&wholeBuffer[fileOffset]);
@@ -1571,83 +2592,276 @@ void OutputFile::writeOutputFile(ld::Internal& state)
                                this->applyFixUps(state, mhAddress, atom, &wholeBuffer[fileOffset]);
                                fileOffsetOfEndOfLastAtom = fileOffset+atom->size();
                                lastAtomUsesNoOps = sectionUsesNops;
+                               lastAtomWasThumb = atom->isThumb();
                        }
                        catch (const char* msg) {
                                if ( atom->file() != NULL )
-                                       throwf("%s in %s from %s", msg, atom->name(), atom->file()->path());
+                                       throwf("%s in '%s' from %s", msg, atom->name(), atom->file()->path());
                                else
-                                       throwf("%s in %s", msg, atom->name());
+                                       throwf("%s in '%s'", msg, atom->name());
                        }
                }
        }
        
-       // compute UUID 
-       if ( _options.UUIDMode() == Options::kUUIDContent ) {
-               const bool log = false;
-               if ( (_options.outputKind() != Options::kObjectFile) || state.someObjectFileHasDwarf ) {
-                       uint8_t digest[CC_MD5_DIGEST_LENGTH];
-                       uint32_t        stabsStringsOffsetStart;
-                       uint32_t        tabsStringsOffsetEnd;
-                       uint32_t        stabsOffsetStart;
-                       uint32_t        stabsOffsetEnd;
-                       if ( _symbolTableAtom->hasStabs(stabsStringsOffsetStart, tabsStringsOffsetEnd, stabsOffsetStart, stabsOffsetEnd) ) {
-                               // find two areas of file that are stabs info and should not contribute to checksum
-                               uint64_t stringPoolFileOffset = 0;
-                               uint64_t symbolTableFileOffset = 0;
-                               for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
-                                       ld::Internal::FinalSection* sect = *sit;
-                                       if ( sect->type() == ld::Section::typeLinkEdit ) {
-                                               if ( strcmp(sect->sectionName(), "__string_pool") == 0 )
-                                                       stringPoolFileOffset = sect->fileOffset;
-                                               else if ( strcmp(sect->sectionName(), "__symbol_table") == 0 )
-                                                       symbolTableFileOffset = sect->fileOffset;
-                                       }
+       if ( _options.verboseOptimizationHints() ) {
+               //fprintf(stderr, "ADRP optimized away:   %d\n", sAdrpNA);
+               //fprintf(stderr, "ADRPs changed to NOPs: %d\n", sAdrpNoped);
+               //fprintf(stderr, "ADRPs unchanged:       %d\n", sAdrpNotNoped);
+       }
+}
+
+void OutputFile::computeContentUUID(ld::Internal& state, uint8_t* wholeBuffer)
+{
+       const bool log = false;
+       if ( (_options.outputKind() != Options::kObjectFile) || state.someObjectFileHasDwarf ) {
+               uint8_t digest[CC_MD5_DIGEST_LENGTH];
+               std::vector<std::pair<uint64_t, uint64_t>> excludeRegions;
+               uint64_t bitcodeCmdOffset;
+               uint64_t bitcodeCmdEnd;
+               uint64_t bitcodeSectOffset;
+               uint64_t bitcodePaddingEnd;
+               if ( _headersAndLoadCommandAtom->bitcodeBundleCommand(bitcodeCmdOffset, bitcodeCmdEnd,
+                                                                                                                         bitcodeSectOffset, bitcodePaddingEnd) ) {
+                       // Exclude embedded bitcode bundle section which contains timestamps in XAR header
+                       // Note the timestamp is in the compressed XML header which means it might change the size of
+                       // bitcode section. The load command which include the size of the section and the padding after
+                       // the bitcode section should also be excluded in the UUID computation.
+                       // Bitcode section should appears before LINKEDIT
+                       // Exclude section cmd
+                       if ( log ) fprintf(stderr, "bundle cmd start=0x%08llX, bundle cmd end=0x%08llX\n",
+                                                          bitcodeCmdOffset, bitcodeCmdEnd);
+                       excludeRegions.emplace_back(std::pair<uint64_t, uint64_t>(bitcodeCmdOffset, bitcodeCmdEnd));
+                       // Exclude section content
+                       if ( log ) fprintf(stderr, "bundle start=0x%08llX, bundle end=0x%08llX\n",
+                                                          bitcodeSectOffset, bitcodePaddingEnd);
+                       excludeRegions.emplace_back(std::pair<uint64_t, uint64_t>(bitcodeSectOffset, bitcodePaddingEnd));
+               }
+               uint32_t        stabsStringsOffsetStart;
+               uint32_t        tabsStringsOffsetEnd;
+               uint32_t        stabsOffsetStart;
+               uint32_t        stabsOffsetEnd;
+               if ( _symbolTableAtom->hasStabs(stabsStringsOffsetStart, tabsStringsOffsetEnd, stabsOffsetStart, stabsOffsetEnd) ) {
+                       // find two areas of file that are stabs info and should not contribute to checksum
+                       uint64_t stringPoolFileOffset = 0;
+                       uint64_t symbolTableFileOffset = 0;
+                       for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+                               ld::Internal::FinalSection* sect = *sit;
+                               if ( sect->type() == ld::Section::typeLinkEdit ) {
+                                       if ( strcmp(sect->sectionName(), "__string_pool") == 0 )
+                                               stringPoolFileOffset = sect->fileOffset;
+                                       else if ( strcmp(sect->sectionName(), "__symbol_table") == 0 )
+                                               symbolTableFileOffset = sect->fileOffset;
+                               }
+                       }
+                       uint64_t firstStabNlistFileOffset  = symbolTableFileOffset + stabsOffsetStart;
+                       uint64_t lastStabNlistFileOffset   = symbolTableFileOffset + stabsOffsetEnd;
+                       uint64_t firstStabStringFileOffset = stringPoolFileOffset  + stabsStringsOffsetStart;
+                       uint64_t lastStabStringFileOffset  = stringPoolFileOffset  + tabsStringsOffsetEnd;
+                       if ( log ) fprintf(stderr, "firstStabNlistFileOffset=0x%08llX\n", firstStabNlistFileOffset);
+                       if ( log ) fprintf(stderr, "lastStabNlistFileOffset=0x%08llX\n", lastStabNlistFileOffset);
+                       if ( log ) fprintf(stderr, "firstStabStringFileOffset=0x%08llX\n", firstStabStringFileOffset);
+                       if ( log ) fprintf(stderr, "lastStabStringFileOffset=0x%08llX\n", lastStabStringFileOffset);
+                       assert(firstStabNlistFileOffset <= firstStabStringFileOffset);
+                       excludeRegions.emplace_back(std::pair<uint64_t, uint64_t>(firstStabNlistFileOffset, lastStabNlistFileOffset));
+                       excludeRegions.emplace_back(std::pair<uint64_t, uint64_t>(firstStabStringFileOffset, lastStabStringFileOffset));
+               }
+               if ( !excludeRegions.empty() ) {
+                       CC_MD5_CTX md5state;
+                       CC_MD5_Init(&md5state);
+                       // rdar://problem/19487042 include the output leaf file name in the hash
+                       const char* lastSlash = strrchr(_options.outputFilePath(), '/');
+                       if ( lastSlash !=  NULL ) {
+                               CC_MD5_Update(&md5state, lastSlash, strlen(lastSlash));
+                       }
+                       uint64_t checksumStart = 0;
+                       for ( auto& region : excludeRegions ) {
+                               uint64_t regionStart = region.first;
+                               uint64_t regionEnd = region.second;
+                               assert(checksumStart <= regionStart && regionStart <= regionEnd && "Region overlapped");
+                               if ( log ) fprintf(stderr, "checksum 0x%08llX -> 0x%08llX\n", checksumStart, regionStart);
+                               CC_MD5_Update(&md5state, &wholeBuffer[checksumStart], regionStart - checksumStart);
+                               checksumStart = regionEnd;
+                       }
+                       if ( log ) fprintf(stderr, "checksum 0x%08llX -> 0x%08llX\n", checksumStart, _fileSize);
+                       CC_MD5_Update(&md5state, &wholeBuffer[checksumStart], _fileSize-checksumStart);
+                       CC_MD5_Final(digest, &md5state);
+                       if ( log ) fprintf(stderr, "uuid=%02X, %02X, %02X, %02X, %02X, %02X, %02X, %02X\n", digest[0], digest[1], digest[2],
+                                                          digest[3], digest[4], digest[5], digest[6],  digest[7]);
+               }
+               else {
+                       CC_MD5(wholeBuffer, _fileSize, digest);
+               }
+               // <rdar://problem/6723729> LC_UUID uuids should conform to RFC 4122 UUID version 4 & UUID version 5 formats
+               digest[6] = ( digest[6] & 0x0F ) | ( 3 << 4 );
+               digest[8] = ( digest[8] & 0x3F ) | 0x80;
+               // update buffer with new UUID
+               _headersAndLoadCommandAtom->setUUID(digest);
+               _headersAndLoadCommandAtom->recopyUUIDCommand();
+       }
+}
+
+static int sDescriptorOfPathToRemove = -1;
+static void removePathAndExit(int sig)
+{
+       if ( sDescriptorOfPathToRemove != -1 ) {
+               char path[MAXPATHLEN];
+               if ( ::fcntl(sDescriptorOfPathToRemove, F_GETPATH, path) == 0 )
+                       ::unlink(path);
+       }
+       fprintf(stderr, "ld: interrupted\n");
+       exit(1);
+}
+       
+void OutputFile::writeOutputFile(ld::Internal& state)
+{
+       // for UNIX conformance, error if file exists and is not writable
+       if ( (access(_options.outputFilePath(), F_OK) == 0) && (access(_options.outputFilePath(), W_OK) == -1) )
+               throwf("can't write output file: %s", _options.outputFilePath());
+
+       mode_t permissions = 0777;
+       if ( _options.outputKind() == Options::kObjectFile )
+               permissions = 0666;
+       mode_t umask = ::umask(0);
+       ::umask(umask); // put back the original umask
+       permissions &= ~umask;
+       // Calling unlink first assures the file is gone so that open creates it with correct permissions
+       // It also handles the case where __options.outputFilePath() file is not writable but its directory is
+       // And it means we don't have to truncate the file when done writing (in case new is smaller than old)
+       // Lastly, only delete existing file if it is a normal file (e.g. not /dev/null).
+       struct stat stat_buf;
+       bool outputIsRegularFile = false;
+       bool outputIsMappableFile = false;
+       if ( stat(_options.outputFilePath(), &stat_buf) != -1 ) {
+               if (stat_buf.st_mode & S_IFREG) {
+                       outputIsRegularFile = true;
+                       // <rdar://problem/12264302> Don't use mmap on non-hfs volumes
+                       struct statfs fsInfo;
+                       if ( statfs(_options.outputFilePath(), &fsInfo) != -1 ) {
+                               if ( strcmp(fsInfo.f_fstypename, "hfs") == 0) {
+                                       (void)unlink(_options.outputFilePath());
+                                       outputIsMappableFile = true;
                                }
-                               uint64_t firstStabNlistFileOffset  = symbolTableFileOffset + stabsOffsetStart;
-                               uint64_t lastStabNlistFileOffset   = symbolTableFileOffset + stabsOffsetEnd;
-                               uint64_t firstStabStringFileOffset = stringPoolFileOffset  + stabsStringsOffsetStart;
-                               uint64_t lastStabStringFileOffset  = stringPoolFileOffset  + tabsStringsOffsetEnd;
-                               if ( log ) fprintf(stderr, "firstStabNlistFileOffset=0x%08llX\n", firstStabNlistFileOffset);
-                               if ( log ) fprintf(stderr, "lastStabNlistFileOffset=0x%08llX\n", lastStabNlistFileOffset);
-                               if ( log ) fprintf(stderr, "firstStabStringFileOffset=0x%08llX\n", firstStabStringFileOffset);
-                               if ( log ) fprintf(stderr, "lastStabStringFileOffset=0x%08llX\n", lastStabStringFileOffset);
-                               assert(firstStabNlistFileOffset <= firstStabStringFileOffset);
-                               
-                               CC_MD5_CTX md5state;
-                               CC_MD5_Init(&md5state);
-                               // checksum everything up to first stabs nlist
-                               if ( log ) fprintf(stderr, "checksum 0x%08X -> 0x%08llX\n", 0, firstStabNlistFileOffset);
-                               CC_MD5_Update(&md5state, &wholeBuffer[0], firstStabNlistFileOffset);
-                               // checkusm everything after last stabs nlist and up to first stabs string
-                               if ( log ) fprintf(stderr, "checksum 0x%08llX -> 0x%08llX\n", lastStabNlistFileOffset, firstStabStringFileOffset);
-                               CC_MD5_Update(&md5state, &wholeBuffer[lastStabNlistFileOffset], firstStabStringFileOffset-lastStabNlistFileOffset);
-                               // checksum everything after last stabs string to end of file
-                               if ( log ) fprintf(stderr, "checksum 0x%08llX -> 0x%08llX\n", lastStabStringFileOffset, _fileSize);
-                               CC_MD5_Update(&md5state, &wholeBuffer[lastStabStringFileOffset], _fileSize-lastStabStringFileOffset);
-                               CC_MD5_Final(digest, &md5state);
-                               if ( log ) fprintf(stderr, "uuid=%02X, %02X, %02X, %02X, %02X, %02X, %02X, %02X\n", digest[0], digest[1], digest[2], 
-                                                                                                                                       digest[3], digest[4], digest[5], digest[6],  digest[7]);
                        }
                        else {
-                               CC_MD5(wholeBuffer, _fileSize, digest);
-                       }
-                       // <rdar://problem/6723729> LC_UUID uuids should conform to RFC 4122 UUID version 4 & UUID version 5 formats
-                       digest[6] = ( digest[6] & 0x0F ) | ( 3 << 4 );
-                       digest[8] = ( digest[8] & 0x3F ) | 0x80;
-                       // update buffer with new UUID
-                       _headersAndLoadCommandAtom->setUUID(digest);
-                       _headersAndLoadCommandAtom->recopyUUIDCommand();
+                               outputIsMappableFile = false;
+                       }
+               } 
+               else {
+                       outputIsRegularFile = false;
+               }
+       }
+       else {
+               // special files (pipes, devices, etc) must already exist
+               outputIsRegularFile = true;
+               // output file does not exist yet
+               char dirPath[PATH_MAX];
+               strcpy(dirPath, _options.outputFilePath());
+               char* end = strrchr(dirPath, '/');
+               if ( end != NULL ) {
+                       end[1] = '\0';
+                       struct statfs fsInfo;
+                       if ( statfs(dirPath, &fsInfo) != -1 ) {
+                               if ( strcmp(fsInfo.f_fstypename, "hfs") == 0) {
+                                       outputIsMappableFile = true;
+                               }
+                       }
+               }
+       }
+       
+       //fprintf(stderr, "outputIsMappableFile=%d, outputIsRegularFile=%d, path=%s\n", outputIsMappableFile, outputIsRegularFile, _options.outputFilePath());
+       
+       int fd;
+       // Construct a temporary path of the form {outputFilePath}.ld_XXXXXX
+       const char filenameTemplate[] = ".ld_XXXXXX";
+       char tmpOutput[PATH_MAX];
+       uint8_t *wholeBuffer;
+       if ( outputIsRegularFile && outputIsMappableFile ) {
+               // <rdar://problem/20959031> ld64 should clean up temporary files on SIGINT
+               ::signal(SIGINT, removePathAndExit);
+
+               strcpy(tmpOutput, _options.outputFilePath());
+               // If the path is too long to add a suffix for a temporary name then
+               // just fall back to using the output path. 
+               if (strlen(tmpOutput)+strlen(filenameTemplate) < PATH_MAX) {
+                       strcat(tmpOutput, filenameTemplate);
+                       fd = mkstemp(tmpOutput);
+                       sDescriptorOfPathToRemove = fd;
+               } 
+               else {
+                       fd = open(tmpOutput, O_RDWR|O_CREAT, permissions);
+               }
+               if ( fd == -1 ) 
+                       throwf("can't open output file for writing '%s', errno=%d", tmpOutput, errno);
+               if ( ftruncate(fd, _fileSize) == -1 ) {
+                       int err = errno;
+                       unlink(tmpOutput);
+                       if ( err == ENOSPC )
+                               throwf("not enough disk space for writing '%s'", _options.outputFilePath());
+                       else
+                               throwf("can't grow file for writing '%s', errno=%d", _options.outputFilePath(), err);
+               }
+               
+               wholeBuffer = (uint8_t *)mmap(NULL, _fileSize, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0);
+               if ( wholeBuffer == MAP_FAILED )
+                       throwf("can't create buffer of %llu bytes for output", _fileSize);
+       } 
+       else {
+               if ( outputIsRegularFile )
+                       fd = open(_options.outputFilePath(),  O_RDWR|O_CREAT, permissions);
+               else
+                       fd = open(_options.outputFilePath(),  O_WRONLY);
+               if ( fd == -1 ) 
+                       throwf("can't open output file for writing: %s, errno=%d", _options.outputFilePath(), errno);
+               // try to allocate buffer for entire output file content
+               wholeBuffer = (uint8_t*)calloc(_fileSize, 1);
+               if ( wholeBuffer == NULL )
+                       throwf("can't create buffer of %llu bytes for output", _fileSize);
+       }
+       
+       if ( _options.UUIDMode() == Options::kUUIDRandom ) {
+               uint8_t bits[16];
+               ::uuid_generate_random(bits);
+               _headersAndLoadCommandAtom->setUUID(bits);
+       }
+
+       writeAtoms(state, wholeBuffer);
+       
+       // compute UUID 
+       if ( _options.UUIDMode() == Options::kUUIDContent )
+               computeContentUUID(state, wholeBuffer);
+
+       if ( outputIsRegularFile && outputIsMappableFile ) {
+               if ( ::chmod(tmpOutput, permissions) == -1 ) {
+                       unlink(tmpOutput);
+                       throwf("can't set permissions on output file: %s, errno=%d", tmpOutput, errno);
                }
+               if ( ::rename(tmpOutput, _options.outputFilePath()) == -1 && strcmp(tmpOutput, _options.outputFilePath()) != 0) {
+                       unlink(tmpOutput);
+                       throwf("can't move output file in place, errno=%d", errno);
+               }
+       } 
+       else {
+               if ( ::write(fd, wholeBuffer, _fileSize) == -1 ) {
+                       throwf("can't write to output file: %s, errno=%d", _options.outputFilePath(), errno);
+               }
+               sDescriptorOfPathToRemove = -1;
+               ::close(fd);
+               // <rdar://problem/13118223> NFS: iOS incremental builds in Xcode 4.6 fail with codesign error
+               // NFS seems to pad the end of the file sometimes.  Calling trunc seems to correct it...
+               ::truncate(_options.outputFilePath(), _fileSize);
        }
 
-       // write whole output file in one chunk
-       int fd = open(_options.outputFilePath(), O_CREAT | O_WRONLY | O_TRUNC, permissions);
-       if ( fd == -1 ) 
-               throwf("can't open output file for writing: %s, errno=%d", _options.outputFilePath(), errno);
-       if ( ::pwrite(fd, wholeBuffer, _fileSize, 0) == -1 )
-               throwf("can't write to output file: %s, errno=%d", _options.outputFilePath(), errno);
-       close(fd);
-       free(wholeBuffer);
+       // Rename symbol map file if needed
+       if ( _options.renameReverseSymbolMap() ) {
+               assert(_options.hideSymbols() && _options.reverseSymbolMapPath() != NULL && "Must hide symbol and specify a path");
+               uuid_string_t UUIDString;
+               const uint8_t* rawUUID = _headersAndLoadCommandAtom->getUUID();
+               uuid_unparse_upper(rawUUID, UUIDString);
+               char outputMapPath[PATH_MAX];
+               sprintf(outputMapPath, "%s/%s.bcsymbolmap", _options.reverseSymbolMapPath(), UUIDString);
+               if ( ::rename(_options.reverseMapTempPath().c_str(), outputMapPath) != 0 )
+                       throwf("could not create bcsymbolmap file: %s", outputMapPath);
+       }
 }
 
 struct AtomByNameSorter
@@ -1658,6 +2872,19 @@ struct AtomByNameSorter
         }
 };
 
+class NotInSet
+{
+public:
+       NotInSet(const std::set<const ld::Atom*>& theSet) : _set(theSet)  {}
+
+       bool operator()(const ld::Atom* atom) const {
+               return ( _set.count(atom) == 0 );
+       }
+private:
+       const std::set<const ld::Atom*>&  _set;
+};
+
+
 void OutputFile::buildSymbolTable(ld::Internal& state)
 {
        unsigned int machoSectionIndex = 0;
@@ -1679,7 +2906,7 @@ void OutputFile::buildSymbolTable(ld::Internal& state)
                                
                        // in -r mode, clarify symbolTableNotInFinalLinkedImages
                        if ( _options.outputKind() == Options::kObjectFile ) {
-                               if ( _options.architecture() == CPU_TYPE_X86_64 ) {
+                               if ( (_options.architecture() == CPU_TYPE_X86_64) || (_options.architecture() == CPU_TYPE_ARM64) ) {
                                        // x86_64 .o files need labels on anonymous literal strings
                                        if ( (sect->type() == ld::Section::typeCString) && (atom->combine() == ld::Atom::combineByNameAndContent) ) {
                                                (const_cast<ld::Atom*>(atom))->setSymbolTableInclusion(ld::Atom::symbolTableIn);
@@ -1693,6 +2920,11 @@ void OutputFile::buildSymbolTable(ld::Internal& state)
                                        else
                                                (const_cast<ld::Atom*>(atom))->setSymbolTableInclusion(ld::Atom::symbolTableIn);
                                }
+                               else if ( sect->type() == ld::Section::typeTempAlias ) {
+                                       assert(_options.outputKind() == Options::kObjectFile);
+                                       _importedAtoms.push_back(atom);
+                                       continue;
+                               }
                                if ( atom->symbolTableInclusion() == ld::Atom::symbolTableNotInFinalLinkedImages )
                                        (const_cast<ld::Atom*>(atom))->setSymbolTableInclusion(ld::Atom::symbolTableIn);
                        }
@@ -1734,6 +2966,10 @@ void OutputFile::buildSymbolTable(ld::Internal& state)
                        if ( atom->symbolTableInclusion() == ld::Atom::symbolTableNotIn ) {
                                continue;  // don't add to symbol table
                        }
+                       if ( (atom->symbolTableInclusion() == ld::Atom::symbolTableInWithRandomAutoStripLabel) 
+                               && (_options.outputKind() != Options::kObjectFile) ) {
+                               continue;  // don't add to symbol table
+                       }
                        
                        if ( (atom->definition() == ld::Atom::definitionTentative) && (_options.outputKind() == Options::kObjectFile) ) {
                                if ( _options.makeTentativeDefinitionsReal() ) {
@@ -1746,28 +2982,7 @@ void OutputFile::buildSymbolTable(ld::Internal& state)
                                }
                                continue;
                        }
-                       
-                       // <rdar://problem/7977374> Add command line options to control symbol weak-def bit on exported symbols                 
-                       if ( _options.hasWeakBitTweaks() && (atom->definition() == ld::Atom::definitionRegular) ) {
-                               const char* name = atom->name();
-                               if ( atom->scope() == ld::Atom::scopeGlobal ) {
-                                       if ( atom->combine() == ld::Atom::combineNever ) {
-                                               if ( _options.forceWeak(name) )
-                                                       (const_cast<ld::Atom*>(atom))->setCombine(ld::Atom::combineByName);
-                                       }
-                                       else if ( atom->combine() == ld::Atom::combineByName ) {
-                                               if ( _options.forceNotWeak(name) )
-                                                       (const_cast<ld::Atom*>(atom))->setCombine(ld::Atom::combineNever);
-                                       }
-                               }
-                               else {
-                                       if ( _options.forceWeakNonWildCard(name) )
-                                               warning("cannot force to be weak, non-external symbol %s", name);
-                                       else if ( _options.forceNotWeakNonWildcard(name) )
-                                               warning("cannot force to be not-weak, non-external symbol %s", name);
-                               }
-                       }
-                       
+
                        switch ( atom->scope() ) {
                                case ld::Atom::scopeTranslationUnit:
                                        if ( _options.keepLocalSymbol(atom->name()) ) { 
@@ -1788,7 +3003,6 @@ void OutputFile::buildSymbolTable(ld::Internal& state)
                                case ld::Atom::scopeLinkageUnit:
                                        if ( _options.outputKind() == Options::kObjectFile ) {
                                                if ( _options.keepPrivateExterns() ) {
-                                                       assert( (atom->combine() == ld::Atom::combineNever) || (atom->combine() == ld::Atom::combineByName) );
                                                        _exportedAtoms.push_back(atom);
                                                }
                                                else if ( _options.keepLocalSymbol(atom->name()) ) {
@@ -1800,25 +3014,55 @@ void OutputFile::buildSymbolTable(ld::Internal& state)
                                                }
                                        }
                                        else {
-                                               if ( _options.keepLocalSymbol(atom->name()) )
+                                               if ( _options.keepLocalSymbol(atom->name()) ) 
+                                                       _localAtoms.push_back(atom);
+                                               // <rdar://problem/5804214> ld should never have a symbol in the non-lazy indirect symbol table with index 0
+                                               // this works by making __mh_execute_header be a local symbol which takes symbol index 0
+                                               else if ( (atom->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip) && !_options.makeCompressedDyldInfo() )
                                                        _localAtoms.push_back(atom);
                                                else
                                                        (const_cast<ld::Atom*>(atom))->setSymbolTableInclusion(ld::Atom::symbolTableNotIn);
                                        }
-                                       break;
+                                       break;
+                       }
+               }
+       }
+       
+       // <rdar://problem/6978069> ld adds undefined symbol from .exp file to binary
+       if ( (_options.outputKind() == Options::kKextBundle) && _options.hasExportRestrictList() ) {
+               // search for referenced undefines
+               std::set<const ld::Atom*> referencedProxyAtoms;
+               for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
+                       ld::Internal::FinalSection* sect = *sit;
+                       for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin();  ait != sect->atoms.end(); ++ait) {
+                               const ld::Atom* atom = *ait;
+                               for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+                                       switch ( fit->binding ) {
+                                               case ld::Fixup::bindingsIndirectlyBound:
+                                                       referencedProxyAtoms.insert(state.indirectBindingTable[fit->u.bindingIndex]);
+                                                       break;
+                                               case ld::Fixup::bindingDirectlyBound:
+                                                       referencedProxyAtoms.insert(fit->u.target);
+                                                       break;
+                                               default:
+                                                       break;
+                                       }
+                               }
                        }
                }
+               // remove any unreferenced _importedAtoms
+               _importedAtoms.erase(std::remove_if(_importedAtoms.begin(), _importedAtoms.end(), NotInSet(referencedProxyAtoms)), _importedAtoms.end());                       
        }
        
        // sort by name
        std::sort(_exportedAtoms.begin(), _exportedAtoms.end(), AtomByNameSorter());
        std::sort(_importedAtoms.begin(), _importedAtoms.end(), AtomByNameSorter());
-       
 }
 
 void OutputFile::addPreloadLinkEdit(ld::Internal& state)
 {
        switch ( _options.architecture() ) {
+#if SUPPORT_ARCH_i386
                case CPU_TYPE_I386:
                        if ( _hasLocalRelocations ) {
                                _localRelocsAtom = new LocalRelocationsAtom<x86>(_options, state, *this);
@@ -1837,6 +3081,8 @@ void OutputFile::addPreloadLinkEdit(ld::Internal& state)
                                stringPoolSection = state.addAtom(*_stringPoolAtom);
                        }
                        break;
+#endif
+#if SUPPORT_ARCH_x86_64
                case CPU_TYPE_X86_64:
                        if ( _hasLocalRelocations ) {
                                _localRelocsAtom = new LocalRelocationsAtom<x86_64>(_options, state, *this);
@@ -1855,6 +3101,8 @@ void OutputFile::addPreloadLinkEdit(ld::Internal& state)
                                stringPoolSection = state.addAtom(*_stringPoolAtom);
                        }
                        break;
+#endif
+#if SUPPORT_ARCH_arm_any
                case CPU_TYPE_ARM:
                        if ( _hasLocalRelocations ) {
                                _localRelocsAtom = new LocalRelocationsAtom<arm>(_options, state, *this);
@@ -1873,8 +3121,29 @@ void OutputFile::addPreloadLinkEdit(ld::Internal& state)
                                stringPoolSection = state.addAtom(*_stringPoolAtom);
                        }
                        break;
+#endif
+#if SUPPORT_ARCH_arm64
+               case CPU_TYPE_ARM64:
+                       if ( _hasLocalRelocations ) {
+                               _localRelocsAtom = new LocalRelocationsAtom<arm64>(_options, state, *this);
+                               localRelocationsSection = state.addAtom(*_localRelocsAtom);
+                       }
+                       if ( _hasExternalRelocations ) {
+                               _externalRelocsAtom = new ExternalRelocationsAtom<arm64>(_options, state, *this);
+                               externalRelocationsSection = state.addAtom(*_externalRelocsAtom);
+                       }
+                       if ( _hasSymbolTable ) {
+                               _indirectSymbolTableAtom = new IndirectSymbolTableAtom<arm64>(_options, state, *this);
+                               indirectSymbolTableSection = state.addAtom(*_indirectSymbolTableAtom);
+                               _symbolTableAtom = new SymbolTableAtom<arm64>(_options, state, *this);
+                               symbolTableSection = state.addAtom(*_symbolTableAtom);
+                               _stringPoolAtom = new StringPoolAtom(_options, state, *this, 4);
+                               stringPoolSection = state.addAtom(*_stringPoolAtom);
+                       }
+                       break;
+#endif
                default:
-                       throw "architecture not supported for -preload";
+                       throw "-preload not supported";
        }
 
 }
@@ -1887,54 +3156,7 @@ void OutputFile::addLinkEdit(ld::Internal& state)
                return addPreloadLinkEdit(state);
        
        switch ( _options.architecture() ) {
-               case CPU_TYPE_POWERPC:
-                       if ( _hasSectionRelocations ) {
-                               _sectionsRelocationsAtom = new SectionRelocationsAtom<ppc>(_options, state, *this);
-                               sectionRelocationsSection = state.addAtom(*_sectionsRelocationsAtom);
-                       }
-                       if ( _hasDyldInfo ) {
-                               _rebasingInfoAtom = new RebaseInfoAtom<ppc>(_options, state, *this);
-                               rebaseSection = state.addAtom(*_rebasingInfoAtom);
-                               
-                               _bindingInfoAtom = new BindingInfoAtom<ppc>(_options, state, *this);
-                               bindingSection = state.addAtom(*_bindingInfoAtom);
-                               
-                               _weakBindingInfoAtom = new WeakBindingInfoAtom<ppc>(_options, state, *this);
-                               weakBindingSection = state.addAtom(*_weakBindingInfoAtom);
-                               
-                               _lazyBindingInfoAtom = new LazyBindingInfoAtom<ppc>(_options, state, *this);
-                               lazyBindingSection = state.addAtom(*_lazyBindingInfoAtom);
-                               
-                               _exportInfoAtom = new ExportInfoAtom<ppc>(_options, state, *this);
-                               exportSection = state.addAtom(*_exportInfoAtom);
-                       }
-                       if ( _hasLocalRelocations ) {
-                               _localRelocsAtom = new LocalRelocationsAtom<ppc>(_options, state, *this);
-                               localRelocationsSection = state.addAtom(*_localRelocsAtom);
-                       }
-                       if ( _hasSplitSegInfo ) {
-                               _splitSegInfoAtom = new SplitSegInfoAtom<ppc>(_options, state, *this);
-                               splitSegInfoSection = state.addAtom(*_splitSegInfoAtom);
-                       }
-                       if ( _hasFunctionStartsInfo ) {
-                               _functionStartsAtom = new FunctionStartsAtom<ppc>(_options, state, *this);
-                               functionStartsSection = state.addAtom(*_functionStartsAtom);
-                       }
-                       if ( _hasSymbolTable ) {
-                               _symbolTableAtom = new SymbolTableAtom<ppc>(_options, state, *this);
-                               symbolTableSection = state.addAtom(*_symbolTableAtom);
-                       }
-                       if ( _hasExternalRelocations ) {
-                               _externalRelocsAtom = new ExternalRelocationsAtom<ppc>(_options, state, *this);
-                               externalRelocationsSection = state.addAtom(*_externalRelocsAtom);
-                       }
-                       if ( _hasSymbolTable ) {
-                               _indirectSymbolTableAtom = new IndirectSymbolTableAtom<ppc>(_options, state, *this);
-                               indirectSymbolTableSection = state.addAtom(*_indirectSymbolTableAtom);
-                               _stringPoolAtom = new StringPoolAtom(_options, state, *this, 4);
-                               stringPoolSection = state.addAtom(*_stringPoolAtom);
-                       }
-                       break;
+#if SUPPORT_ARCH_i386
                case CPU_TYPE_I386:
                        if ( _hasSectionRelocations ) {
                                _sectionsRelocationsAtom = new SectionRelocationsAtom<x86>(_options, state, *this);
@@ -1961,13 +3183,21 @@ void OutputFile::addLinkEdit(ld::Internal& state)
                                localRelocationsSection = state.addAtom(*_localRelocsAtom);
                        }
                        if  ( _hasSplitSegInfo ) {
-                               _splitSegInfoAtom = new SplitSegInfoAtom<x86>(_options, state, *this);
+                               _splitSegInfoAtom = new SplitSegInfoV1Atom<x86>(_options, state, *this);
                                splitSegInfoSection = state.addAtom(*_splitSegInfoAtom);
                        }
                        if ( _hasFunctionStartsInfo ) {
                                _functionStartsAtom = new FunctionStartsAtom<x86>(_options, state, *this);
                                functionStartsSection = state.addAtom(*_functionStartsAtom);
                        }
+                       if ( _hasDataInCodeInfo ) {
+                               _dataInCodeAtom = new DataInCodeAtom<x86>(_options, state, *this);
+                               dataInCodeSection = state.addAtom(*_dataInCodeAtom);
+                       }
+                       if ( _hasOptimizationHints ) {
+                               _optimizationHintsAtom = new OptimizationHintsAtom<x86>(_options, state, *this);
+                               optimizationHintsSection = state.addAtom(*_optimizationHintsAtom);
+                       }
                        if ( _hasSymbolTable ) {
                                _symbolTableAtom = new SymbolTableAtom<x86>(_options, state, *this);
                                symbolTableSection = state.addAtom(*_symbolTableAtom);
@@ -1983,6 +3213,8 @@ void OutputFile::addLinkEdit(ld::Internal& state)
                                stringPoolSection = state.addAtom(*_stringPoolAtom);
                        }
                        break;
+#endif
+#if SUPPORT_ARCH_x86_64
                case CPU_TYPE_X86_64:
                        if ( _hasSectionRelocations ) {
                                _sectionsRelocationsAtom = new SectionRelocationsAtom<x86_64>(_options, state, *this);
@@ -2009,13 +3241,21 @@ void OutputFile::addLinkEdit(ld::Internal& state)
                                localRelocationsSection = state.addAtom(*_localRelocsAtom);
                        }
                        if  ( _hasSplitSegInfo ) {
-                               _splitSegInfoAtom = new SplitSegInfoAtom<x86_64>(_options, state, *this);
+                               _splitSegInfoAtom = new SplitSegInfoV1Atom<x86_64>(_options, state, *this);
                                splitSegInfoSection = state.addAtom(*_splitSegInfoAtom);
                        }
                        if ( _hasFunctionStartsInfo ) {
                                _functionStartsAtom = new FunctionStartsAtom<x86_64>(_options, state, *this);
                                functionStartsSection = state.addAtom(*_functionStartsAtom);
                        }
+                       if ( _hasDataInCodeInfo ) {
+                               _dataInCodeAtom = new DataInCodeAtom<x86_64>(_options, state, *this);
+                               dataInCodeSection = state.addAtom(*_dataInCodeAtom);
+                       }
+                       if ( _hasOptimizationHints ) {
+                               _optimizationHintsAtom = new OptimizationHintsAtom<x86_64>(_options, state, *this);
+                               optimizationHintsSection = state.addAtom(*_optimizationHintsAtom);
+                       }
                        if ( _hasSymbolTable ) {
                                _symbolTableAtom = new SymbolTableAtom<x86_64>(_options, state, *this);
                                symbolTableSection = state.addAtom(*_symbolTableAtom);
@@ -2031,6 +3271,8 @@ void OutputFile::addLinkEdit(ld::Internal& state)
                                stringPoolSection = state.addAtom(*_stringPoolAtom);
                        }
                        break;
+#endif
+#if SUPPORT_ARCH_arm_any
                case CPU_TYPE_ARM:
                        if ( _hasSectionRelocations ) {
                                _sectionsRelocationsAtom = new SectionRelocationsAtom<arm>(_options, state, *this);
@@ -2057,13 +3299,24 @@ void OutputFile::addLinkEdit(ld::Internal& state)
                                localRelocationsSection = state.addAtom(*_localRelocsAtom);
                        }
                        if  ( _hasSplitSegInfo ) {
-                               _splitSegInfoAtom = new SplitSegInfoAtom<arm>(_options, state, *this);
+                               if ( _options.sharedRegionEncodingV2() )
+                                       _splitSegInfoAtom = new SplitSegInfoV2Atom<arm>(_options, state, *this);
+                               else
+                                       _splitSegInfoAtom = new SplitSegInfoV1Atom<arm>(_options, state, *this);
                                splitSegInfoSection = state.addAtom(*_splitSegInfoAtom);
                        }
                        if ( _hasFunctionStartsInfo ) {
                                _functionStartsAtom = new FunctionStartsAtom<arm>(_options, state, *this);
                                functionStartsSection = state.addAtom(*_functionStartsAtom);
                        }
+                       if ( _hasDataInCodeInfo ) {
+                               _dataInCodeAtom = new DataInCodeAtom<arm>(_options, state, *this);
+                               dataInCodeSection = state.addAtom(*_dataInCodeAtom);
+                       }
+                       if ( _hasOptimizationHints ) {
+                               _optimizationHintsAtom = new OptimizationHintsAtom<arm>(_options, state, *this);
+                               optimizationHintsSection = state.addAtom(*_optimizationHintsAtom);
+                       }
                        if ( _hasSymbolTable ) {
                                _symbolTableAtom = new SymbolTableAtom<arm>(_options, state, *this);
                                symbolTableSection = state.addAtom(*_symbolTableAtom);
@@ -2079,54 +3332,68 @@ void OutputFile::addLinkEdit(ld::Internal& state)
                                stringPoolSection = state.addAtom(*_stringPoolAtom);
                        }
                        break;
-               case CPU_TYPE_POWERPC64:
+#endif
+#if SUPPORT_ARCH_arm64
+               case CPU_TYPE_ARM64:
                        if ( _hasSectionRelocations ) {
-                               _sectionsRelocationsAtom = new SectionRelocationsAtom<ppc64>(_options, state, *this);
+                               _sectionsRelocationsAtom = new SectionRelocationsAtom<arm64>(_options, state, *this);
                                sectionRelocationsSection = state.addAtom(*_sectionsRelocationsAtom);
                        }
                        if ( _hasDyldInfo ) {
-                               _rebasingInfoAtom = new RebaseInfoAtom<ppc64>(_options, state, *this);
+                               _rebasingInfoAtom = new RebaseInfoAtom<arm64>(_options, state, *this);
                                rebaseSection = state.addAtom(*_rebasingInfoAtom);
                                
-                               _bindingInfoAtom = new BindingInfoAtom<ppc64>(_options, state, *this);
+                               _bindingInfoAtom = new BindingInfoAtom<arm64>(_options, state, *this);
                                bindingSection = state.addAtom(*_bindingInfoAtom);
                                
-                               _weakBindingInfoAtom = new WeakBindingInfoAtom<ppc64>(_options, state, *this);
+                               _weakBindingInfoAtom = new WeakBindingInfoAtom<arm64>(_options, state, *this);
                                weakBindingSection = state.addAtom(*_weakBindingInfoAtom);
                                
-                               _lazyBindingInfoAtom = new LazyBindingInfoAtom<ppc64>(_options, state, *this);
+                               _lazyBindingInfoAtom = new LazyBindingInfoAtom<arm64>(_options, state, *this);
                                lazyBindingSection = state.addAtom(*_lazyBindingInfoAtom);
                                
-                               _exportInfoAtom = new ExportInfoAtom<ppc64>(_options, state, *this);
+                               _exportInfoAtom = new ExportInfoAtom<arm64>(_options, state, *this);
                                exportSection = state.addAtom(*_exportInfoAtom);
                        }
                        if ( _hasLocalRelocations ) {
-                               _localRelocsAtom = new LocalRelocationsAtom<ppc64>(_options, state, *this);
+                               _localRelocsAtom = new LocalRelocationsAtom<arm64>(_options, state, *this);
                                localRelocationsSection = state.addAtom(*_localRelocsAtom);
                        }
                        if  ( _hasSplitSegInfo ) {
-                               _splitSegInfoAtom = new SplitSegInfoAtom<ppc64>(_options, state, *this);
+                               if ( _options.sharedRegionEncodingV2() )
+                                       _splitSegInfoAtom = new SplitSegInfoV2Atom<arm64>(_options, state, *this);
+                               else
+                                       _splitSegInfoAtom = new SplitSegInfoV1Atom<arm64>(_options, state, *this);
                                splitSegInfoSection = state.addAtom(*_splitSegInfoAtom);
                        }
                        if ( _hasFunctionStartsInfo ) {
-                               _functionStartsAtom = new FunctionStartsAtom<ppc64>(_options, state, *this);
+                               _functionStartsAtom = new FunctionStartsAtom<arm64>(_options, state, *this);
                                functionStartsSection = state.addAtom(*_functionStartsAtom);
                        }
+                       if ( _hasDataInCodeInfo ) {
+                               _dataInCodeAtom = new DataInCodeAtom<arm64>(_options, state, *this);
+                               dataInCodeSection = state.addAtom(*_dataInCodeAtom);
+                       }
+                       if ( _hasOptimizationHints ) {
+                               _optimizationHintsAtom = new OptimizationHintsAtom<arm64>(_options, state, *this);
+                               optimizationHintsSection = state.addAtom(*_optimizationHintsAtom);
+                       }
                        if ( _hasSymbolTable ) {
-                               _symbolTableAtom = new SymbolTableAtom<ppc64>(_options, state, *this);
+                               _symbolTableAtom = new SymbolTableAtom<arm64>(_options, state, *this);
                                symbolTableSection = state.addAtom(*_symbolTableAtom);
                        }
                        if ( _hasExternalRelocations ) {
-                               _externalRelocsAtom = new ExternalRelocationsAtom<ppc64>(_options, state, *this);
+                               _externalRelocsAtom = new ExternalRelocationsAtom<arm64>(_options, state, *this);
                                externalRelocationsSection = state.addAtom(*_externalRelocsAtom);
                        }
                        if ( _hasSymbolTable ) {
-                               _indirectSymbolTableAtom = new IndirectSymbolTableAtom<ppc64>(_options, state, *this);
+                               _indirectSymbolTableAtom = new IndirectSymbolTableAtom<arm64>(_options, state, *this);
                                indirectSymbolTableSection = state.addAtom(*_indirectSymbolTableAtom);
                                _stringPoolAtom = new StringPoolAtom(_options, state, *this, 4);
                                stringPoolSection = state.addAtom(*_stringPoolAtom);
                        }
                        break;
+#endif
                default:
                        throw "unknown architecture";
        }
@@ -2135,26 +3402,30 @@ void OutputFile::addLinkEdit(ld::Internal& state)
 void OutputFile::addLoadCommands(ld::Internal& state)
 {
        switch ( _options.architecture() ) {
+#if SUPPORT_ARCH_x86_64
                case CPU_TYPE_X86_64:
                        _headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom<x86_64>(_options, state, *this);
                        headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom);
                        break;
+#endif
+#if SUPPORT_ARCH_arm_any
                case CPU_TYPE_ARM:
                        _headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom<arm>(_options, state, *this);
                        headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom);
                        break;
-               case CPU_TYPE_I386:
-                       _headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom<x86>(_options, state, *this);
-                       headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom);
-                       break;
-               case CPU_TYPE_POWERPC:
-                       _headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom<ppc>(_options, state, *this);
+#endif
+#if SUPPORT_ARCH_arm64
+               case CPU_TYPE_ARM64:
+                       _headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom<arm64>(_options, state, *this);
                        headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom);
                        break;
-               case CPU_TYPE_POWERPC64:
-                       _headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom<ppc64>(_options, state, *this);
+#endif
+#if SUPPORT_ARCH_i386
+               case CPU_TYPE_I386:
+                       _headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom<x86>(_options, state, *this);
                        headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom);
                        break;
+#endif
                default:
                        throw "unknown architecture";
        }
@@ -2276,9 +3547,13 @@ int OutputFile::compressedOrdinalForAtom(const ld::Atom* target)
 
        // regular ordinal
        const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(target->file());
-       if ( dylib != NULL )
-               return _dylibToOrdinal[dylib]; 
-
+       if ( dylib != NULL ) {
+               std::map<const ld::dylib::File*, int>::iterator pos = _dylibToOrdinal.find(dylib);
+               if ( pos != _dylibToOrdinal.end() )
+                       return pos->second;
+               assert(0 && "dylib not assigned ordinal");
+       }
+       
        // handle undefined dynamic_lookup
        if ( _options.undefinedTreatment() == Options::kUndefinedDynamicLookup )
                return BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
@@ -2310,20 +3585,34 @@ bool OutputFile::isPcRelStore(ld::Fixup::Kind kind)
                case ld::Fixup::kindStoreARMBranch24:
                case ld::Fixup::kindStoreThumbBranch22:
                case ld::Fixup::kindStoreARMLoad12:
-               case ld::Fixup::kindStorePPCBranch24:
-               case ld::Fixup::kindStorePPCBranch14:
-               case ld::Fixup::kindStorePPCPicLow14:
-               case ld::Fixup::kindStorePPCPicLow16:
-               case ld::Fixup::kindStorePPCPicHigh16AddLow:
                case ld::Fixup::kindStoreTargetAddressX86PCRel32:
                case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
                case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
+               case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
+               case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA:
                case ld::Fixup::kindStoreTargetAddressARMBranch24:
                case ld::Fixup::kindStoreTargetAddressThumbBranch22:
                case ld::Fixup::kindStoreTargetAddressARMLoad12:
-               case ld::Fixup::kindStoreTargetAddressPPCBranch24:
+#if SUPPORT_ARCH_arm64
+               case ld::Fixup::kindStoreARM64Page21:
+               case ld::Fixup::kindStoreARM64PageOff12:
+               case ld::Fixup::kindStoreARM64GOTLoadPage21:
+               case ld::Fixup::kindStoreARM64GOTLoadPageOff12:
+               case ld::Fixup::kindStoreARM64GOTLeaPage21:
+               case ld::Fixup::kindStoreARM64GOTLeaPageOff12:
+               case ld::Fixup::kindStoreARM64PCRelToGOT:
+               case ld::Fixup::kindStoreTargetAddressARM64Page21:
+               case ld::Fixup::kindStoreTargetAddressARM64PageOff12:
+               case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
+               case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12:
+               case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21:
+               case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPageOff12:
+#endif
                        return true;
                case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
+#if SUPPORT_ARCH_arm64
+               case ld::Fixup::kindStoreTargetAddressARM64Branch26:
+#endif
                        return (_options.outputKind() != Options::kKextBundle);
                default:
                        break;
@@ -2367,19 +3656,30 @@ bool OutputFile::setsTarget(ld::Fixup::Kind kind)
                case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
                case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
                case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
+               case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
+               case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA:
+               case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad:
                case ld::Fixup::kindStoreTargetAddressARMBranch24:
                case ld::Fixup::kindStoreTargetAddressThumbBranch22:
                case ld::Fixup::kindStoreTargetAddressARMLoad12:
-               case ld::Fixup::kindStoreTargetAddressPPCBranch24:
+#if SUPPORT_ARCH_arm64
+               case ld::Fixup::kindStoreTargetAddressARM64Branch26:
+               case ld::Fixup::kindStoreTargetAddressARM64Page21:
+               case ld::Fixup::kindStoreTargetAddressARM64PageOff12:
+               case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
+               case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12:
+               case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21:
+               case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPageOff12:
+#endif
                        return true;
                case ld::Fixup::kindStoreX86DtraceCallSiteNop:
                case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
                case ld::Fixup::kindStoreARMDtraceCallSiteNop:
                case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear:
+               case ld::Fixup::kindStoreARM64DtraceCallSiteNop:
+               case ld::Fixup::kindStoreARM64DtraceIsEnableSiteClear:
                case ld::Fixup::kindStoreThumbDtraceCallSiteNop:
                case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
-               case ld::Fixup::kindStorePPCDtraceCallSiteNop:
-               case ld::Fixup::kindStorePPCDtraceIsEnableSiteClear:
                        return (_options.outputKind() == Options::kObjectFile);
                default:
                        break;
@@ -2455,13 +3755,14 @@ uint64_t OutputFile::lookBackAddend(ld::Fixup::iterator fit)
 }
 
 
-
-
-
 void OutputFile::generateLinkEditInfo(ld::Internal& state)
 {
        for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
                ld::Internal::FinalSection* sect = *sit;
+               // record end of last __TEXT section encrypted iPhoneOS apps.
+               if ( _options.makeEncryptable() && (strcmp(sect->segmentName(), "__TEXT") == 0) ) { 
+                       _encryptedTEXTendOffset = pageAlign(sect->fileOffset + sect->size);
+               }
                bool objc1ClassRefSection = ( (sect->type() == ld::Section::typeCStringPointer) 
                                                                        && (strcmp(sect->sectionName(), "__cls_refs") == 0)
                                                                        && (strcmp(sect->segmentName(), "__OBJC") == 0) );
@@ -2483,6 +3784,7 @@ void OutputFile::generateLinkEditInfo(ld::Internal& state)
                        ld::Fixup*                      fixupWithTarget = NULL;
                        ld::Fixup*                      fixupWithMinusTarget = NULL;
                        ld::Fixup*                      fixupWithStore = NULL;
+                       ld::Fixup*                      fixupWithAddend = NULL;
                        const ld::Atom*         target = NULL;
                        const ld::Atom*         minusTarget = NULL;
                        uint64_t                        targetAddend = 0;
@@ -2517,9 +3819,11 @@ void OutputFile::generateLinkEditInfo(ld::Internal& state)
                                switch ( fit->kind ) {
                                        case ld::Fixup::kindAddAddend:
                                                targetAddend = fit->u.addend;
+                                               fixupWithAddend = fit;
                                                break;
                                        case ld::Fixup::kindSubtractAddend:
                                                minusTargetAddend = fit->u.addend;
+                                               fixupWithAddend = fit;
                                                break;
                                        case ld::Fixup::kindSubtractTargetAddress:
                                                switch ( fit->binding ) {
@@ -2538,7 +3842,15 @@ void OutputFile::generateLinkEditInfo(ld::Internal& state)
                                                }
                                                assert(minusTarget != NULL);
                                                break;
-                     default:
+                                       case ld::Fixup::kindDataInCodeStartData:
+                                       case ld::Fixup::kindDataInCodeStartJT8:
+                                       case ld::Fixup::kindDataInCodeStartJT16:
+                                       case ld::Fixup::kindDataInCodeStartJT32:
+                                       case ld::Fixup::kindDataInCodeStartJTA32:
+                                       case ld::Fixup::kindDataInCodeEnd:
+                                               hasDataInCode = true;
+                                               break;
+                                       default:
                         break;    
                                }
                                if ( this->isStore(fit->kind) ) {
@@ -2547,7 +3859,7 @@ void OutputFile::generateLinkEditInfo(ld::Internal& state)
                                if ( fit->lastInCluster() ) {
                                        if ( (fixupWithStore != NULL) && (target != NULL) ) {
                                                if ( _options.outputKind() == Options::kObjectFile ) {
-                                                       this->addSectionRelocs(state, sect, atom, fixupWithTarget, fixupWithMinusTarget, fixupWithStore,
+                                                       this->addSectionRelocs(state, sect, atom, fixupWithTarget, fixupWithMinusTarget, fixupWithAddend, fixupWithStore,
                                                                                                        target, minusTarget, targetAddend, minusTargetAddend);
                                                }
                                                else {
@@ -2583,17 +3895,33 @@ void OutputFile::noteTextReloc(const ld::Atom* atom, const ld::Atom* target)
                if ( _options.warnAboutTextRelocs() )
                        warning("text reloc in %s to %s", atom->name(), target->name());
        } 
-       else if ( _options.positionIndependentExecutable() && ((_options.iphoneOSVersionMin() >= ld::iPhone4_3) || (_options.macosxVersionMin() >= ld::mac10_7)) ) {
+       else if ( _options.positionIndependentExecutable() && (_options.outputKind() == Options::kDynamicExecutable) 
+               && ((_options.iOSVersionMin() >= ld::iOS_4_3) || (_options.macosxVersionMin() >= ld::mac10_7)) ) {
                if ( ! this->pieDisabled ) {
-                       warning("PIE disabled. Absolute addressing (perhaps -mdynamic-no-pic) not allowed in code signed PIE, "
+#if SUPPORT_ARCH_arm64
+                       if ( _options.architecture() == CPU_TYPE_ARM64 ) {
+                               const char* demangledName = strdup(_options.demangleSymbol(atom->name()));
+                               throwf("Absolute addressing not allowed in arm64 code but used in '%s' referencing '%s'", demangledName, _options.demangleSymbol(target->name()));
+                       }
+                       else
+#endif
+                        {
+                               warning("PIE disabled. Absolute addressing (perhaps -mdynamic-no-pic) not allowed in code signed PIE, "
                                "but used in %s from %s. " 
                                "To fix this warning, don't compile with -mdynamic-no-pic or link with -Wl,-no_pie", 
                                atom->name(), atom->file()->path());
+                       }
                }
                this->pieDisabled = true;
        }
+       else if ( (target->scope() == ld::Atom::scopeGlobal) && (target->combine() == ld::Atom::combineByName) ) {
+               throwf("illegal text-relocoation (direct reference) to (global,weak) %s in %s from %s in %s", target->name(), target->file()->path(), atom->name(), atom->file()->path());
+       }
        else {
-               throwf("illegal text reloc to %s from %s in %s", target->name(), target->file()->path(), atom->name());
+               if ( (target->file() != NULL) && (atom->file() != NULL) )
+                       throwf("illegal text-relocation to '%s' in %s from '%s' in %s", target->name(), target->file()->path(), atom->name(), atom->file()->path());
+        else
+            throwf("illegal text reloc in '%s' to '%s'", atom->name(), target->name());
        }
 }
 
@@ -2608,8 +3936,28 @@ void OutputFile::addDyldInfo(ld::Internal& state,  ld::Internal::FinalSection* s
        // no need to rebase or bind PCRel stores
        if ( this->isPcRelStore(fixupWithStore->kind) ) {
                // as long as target is in same linkage unit
-               if ( (target == NULL) || (target->definition() != ld::Atom::definitionProxy) )
+               if ( (target == NULL) || (target->definition() != ld::Atom::definitionProxy) ) {
+                       // make sure target is not global and weak
+                       if ( (target->scope() == ld::Atom::scopeGlobal) && (target->combine() == ld::Atom::combineByName) && (target->definition() == ld::Atom::definitionRegular)) {
+                               if ( (atom->section().type() == ld::Section::typeCFI)
+                                       || (atom->section().type() == ld::Section::typeDtraceDOF)
+                                       || (atom->section().type() == ld::Section::typeUnwindInfo) ) {
+                                       // ok for __eh_frame and __uwind_info to use pointer diffs to global weak symbols
+                                       return;
+                               }
+                               // <rdar://problem/13700961> spurious warning when weak function has reference to itself
+                               if ( fixupWithTarget->binding == ld::Fixup::bindingDirectlyBound ) {
+                                       // ok to ignore pc-rel references within a weak function to itself
+                                       return;
+                               }
+                               // Have direct reference to weak-global.  This should be an indrect reference
+                               const char* demangledName = strdup(_options.demangleSymbol(atom->name()));
+                               warning("direct access in %s to global weak symbol %s means the weak symbol cannot be overridden at runtime. "
+                                               "This was likely caused by different translation units being compiled with different visibility settings.",
+                                                 demangledName, _options.demangleSymbol(target->name()));
+                       }
                        return;
+               }
        }
 
        // no need to rebase or bind PIC internal pointer diff
@@ -2623,13 +3971,19 @@ void OutputFile::addDyldInfo(ld::Internal& state,  ld::Internal::FinalSection* s
                        return;
                }
                
-               // make sure target is not global and weak
-               if ( (target->scope() == ld::Atom::scopeGlobal) && (target->combine() == ld::Atom::combineByName)
-                               && (atom->section().type() != ld::Section::typeCFI)
-                               && (atom->section().type() != ld::Section::typeDtraceDOF)
-                               && (atom->section().type() != ld::Section::typeUnwindInfo) ) {
-                       // ok for __eh_frame and __uwind_info to use pointer diffs to global weak symbols
-                       throwf("bad codegen, pointer diff in %s to global weak symbol %s", atom->name(), target->name());
+               // check if target of pointer-diff is global and weak
+               if ( (target->scope() == ld::Atom::scopeGlobal) && (target->combine() == ld::Atom::combineByName) && (target->definition() == ld::Atom::definitionRegular) ) {
+                       if ( (atom->section().type() == ld::Section::typeCFI)
+                               || (atom->section().type() == ld::Section::typeDtraceDOF)
+                               || (atom->section().type() == ld::Section::typeUnwindInfo) ) {
+                               // ok for __eh_frame and __uwind_info to use pointer diffs to global weak symbols
+                               return;
+                       }
+                       // Have direct reference to weak-global.  This should be an indrect reference
+                       const char* demangledName = strdup(_options.demangleSymbol(atom->name()));
+                       warning("direct access in %s to global weak symbol %s means the weak symbol cannot be overridden at runtime. "
+                                       "This was likely caused by different translation units being compiled with different visibility settings.",
+                                        demangledName, _options.demangleSymbol(target->name()));
                }
                return;
        }
@@ -2642,7 +3996,7 @@ void OutputFile::addDyldInfo(ld::Internal& state,  ld::Internal::FinalSection* s
        if ( target == NULL )
                return; 
 
-       bool inReadOnlySeg = ( strcmp(sect->segmentName(), "__TEXT") == 0 );
+       bool inReadOnlySeg = ((_options.initialSegProtection(sect->segmentName()) & VM_PROT_WRITE) == 0);
        bool needsRebase = false;
        bool needsBinding = false;
        bool needsLazyBinding = false;
@@ -2651,7 +4005,7 @@ void OutputFile::addDyldInfo(ld::Internal& state,  ld::Internal::FinalSection* s
        uint8_t rebaseType = REBASE_TYPE_POINTER;
        uint8_t type = BIND_TYPE_POINTER;
        const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(target->file());
-       bool weak_import = ((dylib != NULL) && (fixupWithTarget->weakImport || dylib->willBeWeakLinked()));
+    bool weak_import = (fixupWithTarget->weakImport || ((dylib != NULL) && dylib->forcedWeakLinked()));
        uint64_t address =  atom->finalAddress() + fixupWithTarget->offsetInAtom;
        uint64_t addend = targetAddend - minusTargetAddend;
 
@@ -2677,8 +4031,11 @@ void OutputFile::addDyldInfo(ld::Internal& state,  ld::Internal::FinalSection* s
                                // this will be done by other cluster on lazy pointer atom
                        }
                }
-               else if ( (target->contentType() == ld::Atom::typeResolver) && (target->scope() != ld::Atom::scopeGlobal) ) {
+               else if ( target->contentType() == ld::Atom::typeResolver ) {
                        // <rdar://problem/8553647> Hidden resolver functions should not have lazy binding info
+                       // <rdar://problem/12629331> Resolver function run before initializers when overriding the dyld shared cache
+                       // The lazy pointers used by stubs used when non-lazy binding to a resolver are not normal lazy pointers
+                       // and should not be in lazy binding info.
                        needsLazyBinding = false;
                }
                else {
@@ -2733,6 +4090,9 @@ void OutputFile::addDyldInfo(ld::Internal& state,  ld::Internal::FinalSection* s
                                                needsRebase = false;
                                                needsBinding = true;
                                        }
+                                       else if ( _options.forceCoalesce(target->name()) ) {
+                                               needsWeakBinding = true;
+                                       }
                                }
                                break;
                        case ld::Atom::definitionAbsolute:
@@ -2740,6 +4100,20 @@ void OutputFile::addDyldInfo(ld::Internal& state,  ld::Internal::FinalSection* s
                }
        }
        
+       // <rdar://problem/13828711> if target is an import alias, use base of alias
+       if ( target->isAlias() && (target->definition() == ld::Atom::definitionProxy) ) {
+               for (ld::Fixup::iterator fit = target->fixupsBegin(), end=target->fixupsEnd(); fit != end; ++fit) {
+                       if ( fit->firstInCluster() ) {
+                               if ( fit->kind == ld::Fixup::kindNoneFollowOn ) {
+                                       if ( fit->binding == ld::Fixup::bindingDirectlyBound ) {
+                                               //fprintf(stderr, "switching import of %s to import of %s\n", target->name(),  fit->u.target->name());
+                                               target = fit->u.target;
+                                       }
+                               }
+                       }
+               }
+       } 
+
        // record dyld info for this cluster
        if ( needsRebase ) {
                if ( inReadOnlySeg ) {
@@ -2747,6 +4121,28 @@ void OutputFile::addDyldInfo(ld::Internal& state,  ld::Internal::FinalSection* s
                        sect->hasLocalRelocs = true;  // so dyld knows to change permissions on __TEXT segment
                        rebaseType = REBASE_TYPE_TEXT_ABSOLUTE32;
                }
+               if ( _options.sharedRegionEligible() ) {
+                       // <rdar://problem/13287063> when range checking, ignore high byte of arm64 addends
+                       uint64_t checkAddend = addend;
+                       if ( _options.architecture() == CPU_TYPE_ARM64 )
+                               checkAddend &= 0x0FFFFFFFFFFFFFFFULL;
+                       if ( checkAddend != 0 ) {
+                               // make sure the addend does not cause the pointer to point outside the target's segment
+                               // if it does, update_dyld_shared_cache will not be able to put this dylib into the shared cache
+                               uint64_t targetAddress = target->finalAddress();
+                               for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+                                       ld::Internal::FinalSection* sct = *sit;
+                                       uint64_t sctEnd = (sct->address+sct->size);
+                                       if ( (sct->address <= targetAddress) && (targetAddress < sctEnd) ) {
+                                               if ( (targetAddress+checkAddend) > sctEnd ) {
+                                                       warning("data symbol %s from %s has pointer to %s + 0x%08llX. "  
+                                                                       "That large of an addend may disable %s from being put in the dyld shared cache.", 
+                                                                       atom->name(), atom->file()->path(), target->name(), addend, _options.installPath() );
+                                               }
+                                       }
+                               }
+                       }
+               }
                _rebaseInfo.push_back(RebaseInfo(rebaseType, address));
        }
        if ( needsBinding ) {
@@ -2764,10 +4160,6 @@ void OutputFile::addDyldInfo(ld::Internal& state,  ld::Internal::FinalSection* s
        }
        if ( needsWeakBinding )
                _weakBindingInfo.push_back(BindingInfo(type, 0, target->name(), false, address, addend));
-
-       // record if weak imported  
-       if ( weak_import && (target->definition() == ld::Atom::definitionProxy) )
-               (const_cast<ld::Atom*>(target))->setWeakImported();
 }
 
 
@@ -2780,14 +4172,20 @@ void OutputFile::addClassicRelocs(ld::Internal& state, ld::Internal::FinalSectio
                return;
        
        // non-lazy-pointer section is encoded in indirect symbol table - not using relocations
-       if ( (sect->type() == ld::Section::typeNonLazyPointer) && (_options.outputKind() != Options::kKextBundle) ) {
-               assert(target != NULL);
-               assert(fixupWithTarget != NULL);
-               // record if weak imported  
-               const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(target->file());
-               if ( (dylib != NULL) && (fixupWithTarget->weakImport || dylib->willBeWeakLinked()) )
-                       (const_cast<ld::Atom*>(target))->setWeakImported();
-               return;
+       if ( sect->type() == ld::Section::typeNonLazyPointer ) {
+               // except kexts and static pie which *do* use relocations
+               switch (_options.outputKind()) {
+                       case Options::kKextBundle:
+                               break;
+                       case Options::kStaticExecutable:
+                               if ( _options.positionIndependentExecutable() )
+                                       break;
+                               // else fall into default case
+                       default:
+                               assert(target != NULL);
+                               assert(fixupWithTarget != NULL);
+                               return;
+               }
        }
        
        // no need to rebase or bind PCRel stores
@@ -2828,12 +4226,7 @@ void OutputFile::addClassicRelocs(ld::Internal& state, ld::Internal::FinalSectio
 
        switch ( fixupWithStore->kind ) {
                case ld::Fixup::kindLazyTarget:
-                       {
-                               // lazy pointers don't need relocs, but might need weak_import bit set
-                               const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(target->file());
-                               if ( (dylib != NULL) && (fixupWithTarget->weakImport || dylib->willBeWeakLinked()) )
-                                       (const_cast<ld::Atom*>(target))->setWeakImported();
-                       }
+                       // lazy pointers don't need relocs
                        break;
                case ld::Fixup::kindStoreLittleEndian32:
                case ld::Fixup::kindStoreLittleEndian64:
@@ -2859,7 +4252,9 @@ void OutputFile::addClassicRelocs(ld::Internal& state, ld::Internal::FinalSectio
                                        // reference to global weak def needs weak binding in dynamic images
                                        if ( (target->combine() == ld::Atom::combineByName) 
                                                && (target->definition() == ld::Atom::definitionRegular)
-                                               && (_options.outputKind() != Options::kStaticExecutable) ) {
+                                               && (_options.outputKind() != Options::kStaticExecutable)
+                                               && (_options.outputKind() != Options::kPreload) 
+                                               && (atom != target) ) {
                                                needsExternReloc = true;
                                        }
                                        else if ( _options.outputKind() == Options::kDynamicExecutable ) {
@@ -2893,9 +4288,6 @@ void OutputFile::addClassicRelocs(ld::Internal& state, ld::Internal::FinalSectio
                                _externalRelocsAtom->addExternalPointerReloc(relocAddress, target);
                                sect->hasExternalRelocs = true;
                                fixupWithTarget->contentAddendOnly = true;
-                               // record if weak imported  
-                               if ( (dylib != NULL) && (fixupWithTarget->weakImport || dylib->willBeWeakLinked()) )
-                                       (const_cast<ld::Atom*>(target))->setWeakImported();
                        }
                        else if ( needsLocalReloc ) {
                                assert(target != NULL);
@@ -2905,26 +4297,10 @@ void OutputFile::addClassicRelocs(ld::Internal& state, ld::Internal::FinalSectio
                                sect->hasLocalRelocs = true;
                        }
                        break;
-               case ld::Fixup::kindStorePPCAbsLow14:
-               case ld::Fixup::kindStorePPCAbsLow16:
-               case ld::Fixup::kindStorePPCAbsHigh16AddLow:
-               case ld::Fixup::kindStorePPCAbsHigh16:
-                       {
-                               assert(target != NULL);
-                               if ( target->definition() == ld::Atom::definitionProxy )
-                                       throwf("half word text relocs not supported in %s", atom->name());
-                               if ( _options.outputSlidable() ) {
-                                       if ( inReadOnlySeg )
-                                               noteTextReloc(atom, target);
-                                       uint32_t machoSectionIndex = (target->definition() == ld::Atom::definitionAbsolute) 
-                                                                                                       ? R_ABS : target->machoSection();
-                                       _localRelocsAtom->addTextReloc(relocAddress, fixupWithTarget->kind,  
-                                                                                                       target->finalAddress(), machoSectionIndex);
-                                       sect->hasLocalRelocs = true;
-                               }
-                       }
-                       break;
                case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
+#if SUPPORT_ARCH_arm64
+               case ld::Fixup::kindStoreTargetAddressARM64Branch26:
+#endif
                        if ( _options.outputKind() == Options::kKextBundle ) {
                                assert(target != NULL);
                                if ( target->definition() == ld::Atom::definitionProxy ) {
@@ -2933,6 +4309,21 @@ void OutputFile::addClassicRelocs(ld::Internal& state, ld::Internal::FinalSectio
                                }
                        }
                        break;
+               
+               case ld::Fixup::kindStoreARMLow16:
+               case ld::Fixup::kindStoreThumbLow16:
+                       // no way to encode rebasing of binding for these instructions
+                       if ( _options.outputSlidable() || (target->definition() == ld::Atom::definitionProxy) )
+                               throwf("no supported runtime lo16 relocation in %s from %s to %s", atom->name(), atom->file()->path(), target->name());
+                       break;
+                               
+               case ld::Fixup::kindStoreARMHigh16:
+               case ld::Fixup::kindStoreThumbHigh16:
+                       // no way to encode rebasing of binding for these instructions
+                       if ( _options.outputSlidable() || (target->definition() == ld::Atom::definitionProxy) )
+                               throwf("no supported runtime hi16 relocation in %s from %s to %s", atom->name(), atom->file()->path(), target->name());
+                       break;
+
                default:
                        break;
        }
@@ -2941,10 +4332,31 @@ void OutputFile::addClassicRelocs(ld::Internal& state, ld::Internal::FinalSectio
 
 bool OutputFile::useExternalSectionReloc(const ld::Atom* atom, const ld::Atom* target, ld::Fixup* fixupWithTarget)
 {
-       if ( _options.architecture() == CPU_TYPE_X86_64 ) {
-               // x86_64 uses external relocations for everthing that has a symbol
+       if ( (_options.architecture() == CPU_TYPE_X86_64) || (_options.architecture() == CPU_TYPE_ARM64) ) {
+               // x86_64 and ARM64 use external relocations for everthing that has a symbol
                return ( target->symbolTableInclusion() != ld::Atom::symbolTableNotIn );
        }
+       
+       // <rdar://problem/9513487> support arm branch interworking in -r mode 
+       if ( (_options.architecture() == CPU_TYPE_ARM) && (_options.outputKind() == Options::kObjectFile) ) {
+               if ( atom->isThumb() != target->isThumb() ) {
+                       switch ( fixupWithTarget->kind ) {
+                               // have branch that switches mode, then might be 'b' not 'bl'
+                               // Force external relocation, since no way to do local reloc for 'b'
+                               case ld::Fixup::kindStoreTargetAddressThumbBranch22 :
+                               case ld::Fixup::kindStoreTargetAddressARMBranch24:
+                                       return true;
+                               default:
+                                       break;
+                       }
+               }
+       }
+       
+       if ( (_options.architecture() == CPU_TYPE_I386) && (_options.outputKind() == Options::kObjectFile) ) {
+               if ( target->contentType() == ld::Atom::typeTLV ) 
+                       return true;
+       }
+
        // most architectures use external relocations only for references
        // to a symbol in another translation unit or for references to "weak symbols" or tentative definitions
        assert(target != NULL);
@@ -2959,11 +4371,29 @@ bool OutputFile::useExternalSectionReloc(const ld::Atom* atom, const ld::Atom* t
        return false;
 }
 
+bool OutputFile::useSectionRelocAddend(ld::Fixup* fixupWithTarget)
+{
+#if SUPPORT_ARCH_arm64
+       if ( _options.architecture() == CPU_TYPE_ARM64 ) {
+               switch ( fixupWithTarget->kind ) {
+                       case ld::Fixup::kindStoreARM64Branch26:
+                       case ld::Fixup::kindStoreARM64Page21:
+                       case ld::Fixup::kindStoreARM64PageOff12:
+                               return true;
+                       default:
+                               return false;
+               }
+       }
+#endif
+       return false;
+}
+
 
 
 
 void OutputFile::addSectionRelocs(ld::Internal& state, ld::Internal::FinalSection* sect, const ld::Atom* atom, 
-                                                               ld::Fixup* fixupWithTarget, ld::Fixup* fixupWithMinusTarget, ld::Fixup* fixupWithStore,
+                                                               ld::Fixup* fixupWithTarget, ld::Fixup* fixupWithMinusTarget,  
+                                                               ld::Fixup* fixupWithAddend, ld::Fixup* fixupWithStore, 
                                                                const ld::Atom* target, const ld::Atom* minusTarget, 
                                                                uint64_t targetAddend, uint64_t minusTargetAddend)
 {
@@ -2987,11 +4417,13 @@ void OutputFile::addSectionRelocs(ld::Internal& state, ld::Internal::FinalSectio
        bool targetUsesExternalReloc = this->useExternalSectionReloc(atom, target, fixupWithTarget);
        bool minusTargetUsesExternalReloc = (minusTarget != NULL) && this->useExternalSectionReloc(atom, minusTarget, fixupWithMinusTarget);
        
-       // in x86_64 .o files an external reloc means the content contains just the addend
-       if ( _options.architecture() == CPU_TYPE_X86_64 ) {
+       // in x86_64 and arm64 .o files an external reloc means the content contains just the addend
+       if ( (_options.architecture() == CPU_TYPE_X86_64) ||(_options.architecture() == CPU_TYPE_ARM64)  ) {
                if ( targetUsesExternalReloc ) {
                        fixupWithTarget->contentAddendOnly = true;
                        fixupWithStore->contentAddendOnly = true;
+                       if ( this->useSectionRelocAddend(fixupWithStore) && (fixupWithAddend != NULL) )
+                               fixupWithAddend->contentIgnoresAddend = true;
                }
                if ( minusTargetUsesExternalReloc )
                        fixupWithMinusTarget->contentAddendOnly = true;
@@ -3001,7 +4433,15 @@ void OutputFile::addSectionRelocs(ld::Internal& state, ld::Internal::FinalSectio
                // pc-rel instructions are funny. If the target is _foo+8 and _foo is 
                // external, then the pc-rel instruction *evalutates* to the address 8.
                if ( targetUsesExternalReloc ) {
-                       if ( isPcRelStore(fixupWithStore->kind) ) {
+                       // TLV support for i386 acts like RIP relative addressing
+                       // The addend is the offset from the PICBase to the end of the instruction 
+                       if ( (_options.architecture() == CPU_TYPE_I386) 
+                                && (_options.outputKind() == Options::kObjectFile)
+                            && (fixupWithStore->kind == ld::Fixup::kindStoreX86PCRel32TLVLoad) ) {
+                               fixupWithTarget->contentAddendOnly = true;
+                               fixupWithStore->contentAddendOnly = true;
+                       }
+                       else if ( isPcRelStore(fixupWithStore->kind) ) {
                                fixupWithTarget->contentDetlaToAddendOnly = true;
                                fixupWithStore->contentDetlaToAddendOnly = true;
                        }
@@ -3020,7 +4460,6 @@ void OutputFile::addSectionRelocs(ld::Internal& state, ld::Internal::FinalSectio
 
 }
 
-
 void OutputFile::makeSplitSegInfo(ld::Internal& state)
 {
        if ( !_options.sharedRegionEligible() )
@@ -3035,27 +4474,30 @@ void OutputFile::makeSplitSegInfo(ld::Internal& state)
                for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
                        const ld::Atom* atom = *ait;
                        const ld::Atom* target = NULL;
+                       const ld::Atom* fromTarget = NULL;
+            uint64_t accumulator = 0;
+            bool thumbTarget;
                        bool hadSubtract = false;
                        for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
                                if ( fit->firstInCluster() ) 
                                        target = NULL;
-                               if ( fit->kind == ld::Fixup::kindSubtractTargetAddress ) {
-                                       hadSubtract = true;
-                                       continue;
+                               if ( this->setsTarget(fit->kind) ) {
+                                       accumulator = addressOf(state, fit, &target);                   
+                                       thumbTarget = targetIsThumb(state, fit);
+                                       if ( thumbTarget ) 
+                                               accumulator |= 1;
                                }
-                               switch ( fit->binding ) {
-                                       case ld::Fixup::bindingNone:
-                                       case ld::Fixup::bindingByNameUnbound:
+                               switch ( fit->kind ) {
+                                       case ld::Fixup::kindSubtractTargetAddress:
+                        accumulator -= addressOf(state, fit, &fromTarget);
+                                               hadSubtract = true;
                                                break;
-                                       case ld::Fixup::bindingByContentBound:
-                                       case ld::Fixup::bindingDirectlyBound:
-                                               target = fit->u.target;
+                    case ld::Fixup::kindAddAddend:
+                                               accumulator += fit->u.addend;
                                                break;
-                                       case ld::Fixup::bindingsIndirectlyBound:
-                                               target = state.indirectBindingTable[fit->u.bindingIndex];
+                    case ld::Fixup::kindSubtractAddend:
+                                               accumulator -= fit->u.addend;
                                                break;
-                               }
-                               switch ( fit->kind ) {
                                        case ld::Fixup::kindStoreBigEndian32:
                                        case ld::Fixup::kindStoreLittleEndian32:
                                        case ld::Fixup::kindStoreLittleEndian64:
@@ -3065,6 +4507,7 @@ void OutputFile::makeSplitSegInfo(ld::Internal& state)
                                                // there is also a text reloc which update_dyld_shared_cache will use.
                                                if ( ! hadSubtract )
                                                        break;
+                                               // fall through
                                        case ld::Fixup::kindStoreX86PCRel32:
                                        case ld::Fixup::kindStoreX86PCRel32_1:
                                        case ld::Fixup::kindStoreX86PCRel32_2:
@@ -3072,18 +4515,224 @@ void OutputFile::makeSplitSegInfo(ld::Internal& state)
                                        case ld::Fixup::kindStoreX86PCRel32GOTLoad:
                                        case ld::Fixup::kindStoreX86PCRel32GOTLoadNowLEA:
                                        case ld::Fixup::kindStoreX86PCRel32GOT:
-                                       case ld::Fixup::kindStorePPCPicHigh16AddLow:
+                                       case ld::Fixup::kindStoreX86PCRel32TLVLoad:
+                                       case ld::Fixup::kindStoreX86PCRel32TLVLoadNowLEA:
                                        case ld::Fixup::kindStoreTargetAddressX86PCRel32:
                                        case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
                                        case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
+                                       case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
+                                       case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA:
+                    case ld::Fixup::kindStoreARMLow16:
+                    case ld::Fixup::kindStoreThumbLow16: 
+#if SUPPORT_ARCH_arm64
+                                       case ld::Fixup::kindStoreARM64Page21:
+                                       case ld::Fixup::kindStoreARM64GOTLoadPage21:
+                                       case ld::Fixup::kindStoreARM64GOTLeaPage21:
+                                       case ld::Fixup::kindStoreARM64TLVPLoadPage21:
+                                       case ld::Fixup::kindStoreTargetAddressARM64Page21:
+                                       case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
+                                       case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21:
+                                       case ld::Fixup::kindStoreARM64PCRelToGOT:
+#endif
                                                assert(target != NULL);
                                                if ( strcmp(sect->segmentName(), target->section().segmentName()) != 0 ) {      
                                                        _splitSegInfos.push_back(SplitSegInfoEntry(atom->finalAddress()+fit->offsetInAtom,fit->kind));
                                                }
                                                break;
+                    case ld::Fixup::kindStoreARMHigh16: 
+                    case ld::Fixup::kindStoreThumbHigh16: 
+                                               assert(target != NULL);
+                                               if ( strcmp(sect->segmentName(), target->section().segmentName()) != 0 ) {
+                            // hi16 needs to know upper 4-bits of low16 to compute carry
+                            uint32_t extra = (accumulator >> 12) & 0xF;
+                                                       _splitSegInfos.push_back(SplitSegInfoEntry(atom->finalAddress()+fit->offsetInAtom,fit->kind, extra));
+                                               }
+                                               break;
+                                       case ld::Fixup::kindSetTargetImageOffset:
+                                               accumulator = addressOf(state, fit, &target);                   
+                                               assert(target != NULL);
+                                               hadSubtract = true;
+                                               break;
+                                       default:
+                                               break;
+                               }
+                       }
+               }
+       }
+}
+
+void OutputFile::makeSplitSegInfoV2(ld::Internal& state)
+{
+       static const bool log = false;
+       if ( !_options.sharedRegionEligible() )
+               return;
+       
+       for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+               ld::Internal::FinalSection* sect = *sit;
+               if ( sect->isSectionHidden() )
+                       continue;
+               bool codeSection = (sect->type() == ld::Section::typeCode);
+               if (log) fprintf(stderr, "sect: %s, address=0x%llX\n", sect->sectionName(), sect->address);
+               for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+                       const ld::Atom* atom = *ait;
+                       const ld::Atom* target = NULL;
+                       const ld::Atom* fromTarget = NULL;
+                       uint32_t picBase = 0;
+            uint64_t accumulator = 0;
+            bool thumbTarget;
+                       bool hadSubtract = false;
+                       uint8_t fromSectionIndex = atom->machoSection();
+                       uint8_t toSectionIndex;
+                       uint8_t kind = 0;
+                       uint64_t fromOffset = 0;
+                       uint64_t toOffset = 0;
+                       uint64_t addend = 0;
+                       for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+                               if ( fit->firstInCluster() ) {
+                                       target = NULL;
+                                       fromTarget = NULL;
+                                       kind = 0;
+                                       addend = 0;
+                                       toSectionIndex = 255;
+                                       fromOffset = atom->finalAddress() + fit->offsetInAtom - sect->address;
+                               }
+                               if ( this->setsTarget(fit->kind) ) {
+                                       accumulator = addressOf(state, fit, &target);                   
+                                       thumbTarget = targetIsThumb(state, fit);
+                                       if ( thumbTarget ) 
+                                               accumulator |= 1;
+                                       toOffset = accumulator - state.atomToSection[target]->address;
+                                       if ( target->definition() != ld::Atom::definitionProxy ) {
+                                               if ( target->section().type() == ld::Section::typeMachHeader )
+                                                       toSectionIndex = 0;
+                                               else
+                                                       toSectionIndex = target->machoSection();
+                                       }
+                               }
+                               switch ( fit->kind ) {
+                                       case ld::Fixup::kindSubtractTargetAddress:
+                        accumulator -= addressOf(state, fit, &fromTarget);
+                                               hadSubtract = true;
+                                               break;
+                    case ld::Fixup::kindAddAddend:
+                                               accumulator += fit->u.addend;
+                                               addend = fit->u.addend;
+                                               break;
+                    case ld::Fixup::kindSubtractAddend:
+                                               accumulator -= fit->u.addend;
+                                               picBase = fit->u.addend;
+                                               break;
+                                       case ld::Fixup::kindSetLazyOffset:
+                                               break;
+                                       case ld::Fixup::kindStoreBigEndian32:
+                                       case ld::Fixup::kindStoreLittleEndian32:
+                                       case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+                                               if ( kind != DYLD_CACHE_ADJ_V2_IMAGE_OFF_32 ) {
+                                                       if ( hadSubtract )
+                                                               kind = DYLD_CACHE_ADJ_V2_DELTA_32;
+                                                       else
+                                                               kind = DYLD_CACHE_ADJ_V2_POINTER_32;
+                                               }
+                                               break;
+                                       case ld::Fixup::kindStoreLittleEndian64:
+                                       case ld::Fixup::kindStoreTargetAddressLittleEndian64:
+                                               if ( hadSubtract )
+                                                       kind = DYLD_CACHE_ADJ_V2_DELTA_64;
+                                               else
+                                                       kind = DYLD_CACHE_ADJ_V2_POINTER_64;
+                                               break;
+                                       case ld::Fixup::kindStoreX86PCRel32:
+                                       case ld::Fixup::kindStoreX86PCRel32_1:
+                                       case ld::Fixup::kindStoreX86PCRel32_2:
+                                       case ld::Fixup::kindStoreX86PCRel32_4:
+                                       case ld::Fixup::kindStoreX86PCRel32GOTLoad:
+                                       case ld::Fixup::kindStoreX86PCRel32GOTLoadNowLEA:
+                                       case ld::Fixup::kindStoreX86PCRel32GOT:
+                                       case ld::Fixup::kindStoreX86PCRel32TLVLoad:
+                                       case ld::Fixup::kindStoreX86PCRel32TLVLoadNowLEA:
+                                       case ld::Fixup::kindStoreTargetAddressX86PCRel32:
+                                       case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
+                                       case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
+                                       case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
+                                       case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA:
+#if SUPPORT_ARCH_arm64
+                                       case ld::Fixup::kindStoreARM64PCRelToGOT:
+#endif
+                                               if ( (fromSectionIndex != toSectionIndex) || !codeSection )
+                                                       kind = DYLD_CACHE_ADJ_V2_DELTA_32;
+                                               break;
+#if SUPPORT_ARCH_arm64
+                                       case ld::Fixup::kindStoreARM64Page21:
+                                       case ld::Fixup::kindStoreARM64GOTLoadPage21:
+                                       case ld::Fixup::kindStoreARM64GOTLeaPage21:
+                                       case ld::Fixup::kindStoreARM64TLVPLoadPage21:
+                                       case ld::Fixup::kindStoreTargetAddressARM64Page21:
+                                       case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
+                                       case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21:
+                                               if ( fromSectionIndex != toSectionIndex )
+                                                       kind = DYLD_CACHE_ADJ_V2_ARM64_ADRP;
+                                               break;
+                                       case ld::Fixup::kindStoreARM64PageOff12:
+                                       case ld::Fixup::kindStoreARM64GOTLeaPageOff12:
+                                       case ld::Fixup::kindStoreARM64TLVPLoadNowLeaPageOff12:
+                                       case ld::Fixup::kindStoreTargetAddressARM64PageOff12:
+                                       case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPageOff12:
+                                       case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12:
+                                       case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPageOff12:
+                                       case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPageOff12:
+                                               if ( fromSectionIndex != toSectionIndex )
+                                                       kind = DYLD_CACHE_ADJ_V2_ARM64_OFF12;
+                                               break;
+                                       case ld::Fixup::kindStoreARM64Branch26:
+                                       case ld::Fixup::kindStoreTargetAddressARM64Branch26:
+                                               if ( fromSectionIndex != toSectionIndex )
+                                                       kind = DYLD_CACHE_ADJ_V2_ARM64_BR26;
+                                               break;
+#endif
+                    case ld::Fixup::kindStoreARMHigh16:
+                    case ld::Fixup::kindStoreARMLow16:
+                                               if ( (fromSectionIndex != toSectionIndex) && (fromTarget == atom) ) {
+                                                       kind = DYLD_CACHE_ADJ_V2_ARM_MOVW_MOVT;
+                                               }
+                                               break;
+                                       case ld::Fixup::kindStoreARMBranch24:
+                                       case ld::Fixup::kindStoreTargetAddressARMBranch24:
+                                               if ( fromSectionIndex != toSectionIndex )
+                                                       kind = DYLD_CACHE_ADJ_V2_ARM_BR24;
+                                               break;
+                    case ld::Fixup::kindStoreThumbLow16:
+                    case ld::Fixup::kindStoreThumbHigh16:
+                                               if ( (fromSectionIndex != toSectionIndex) && (fromTarget == atom) ) {
+                                                       kind = DYLD_CACHE_ADJ_V2_THUMB_MOVW_MOVT;
+                                               }
+                                               break;
+                                       case ld::Fixup::kindStoreThumbBranch22:
+                                       case ld::Fixup::kindStoreTargetAddressThumbBranch22:
+                                               if ( fromSectionIndex != toSectionIndex )
+                                                       kind = DYLD_CACHE_ADJ_V2_THUMB_BR22;
+                                               break;
+                                       case ld::Fixup::kindSetTargetImageOffset:
+                                               kind = DYLD_CACHE_ADJ_V2_IMAGE_OFF_32;
+                                               accumulator = addressOf(state, fit, &target);                   
+                                               assert(target != NULL);
+                                               toSectionIndex = target->machoSection();
+                                               toOffset = accumulator - state.atomToSection[target]->address;
+                                               hadSubtract = true;
+                                               break;
                                        default:
                                                break;
                                }
+                               if ( fit->lastInCluster() ) {
+                                       if ( (kind != 0) && (target != NULL) && (target->definition() != ld::Atom::definitionProxy) ) {
+                                               if ( !hadSubtract && addend )
+                                                       toOffset += addend;
+                                               assert(toSectionIndex != 255);
+                                               if (log) fprintf(stderr, "from (%d.%s + 0x%llX) to (%d.%s + 0x%llX), kind=%d, atomAddr=0x%llX, sectAddr=0x%llx\n",
+                                                                               fromSectionIndex, sect->sectionName(), fromOffset, toSectionIndex, state.atomToSection[target]->sectionName(),
+                                                                               toOffset, kind, atom->finalAddress(), sect->address);
+                                               _splitSegV2Infos.push_back(SplitSegInfoV2Entry(fromSectionIndex, fromOffset, toSectionIndex, toOffset, kind));
+                                       }
+                               }
                        }
                }
        }
@@ -3107,8 +4756,8 @@ void OutputFile::writeMapFile(ld::Internal& state)
                        //              uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
                        //}
                        // write table of object files
-                       std::map<const ld::File*, uint32_t> readerToOrdinal;
-                       std::map<uint32_t, const ld::File*> ordinalToReader;
+                       std::map<const ld::File*, ld::File::Ordinal> readerToOrdinal;
+                       std::map<ld::File::Ordinal, const ld::File*> ordinalToReader;
                        std::map<const ld::File*, uint32_t> readerToFileOrdinal;
                        for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
                                ld::Internal::FinalSection* sect = *sit;
@@ -3119,8 +4768,8 @@ void OutputFile::writeMapFile(ld::Internal& state)
                                        const ld::File* reader = atom->file();
                                        if ( reader == NULL )
                                                continue;
-                                       uint32_t readerOrdinal = reader->ordinal();
-                                       std::map<const ld::File*, uint32_t>::iterator pos = readerToOrdinal.find(reader);
+                                       ld::File::Ordinal readerOrdinal = reader->ordinal();
+                                       std::map<const ld::File*, ld::File::Ordinal>::iterator pos = readerToOrdinal.find(reader);
                                        if ( pos == readerToOrdinal.end() ) {
                                                readerToOrdinal[reader] = readerOrdinal;
                                                ordinalToReader[readerOrdinal] = reader;
@@ -3129,13 +4778,10 @@ void OutputFile::writeMapFile(ld::Internal& state)
                        }
                        fprintf(mapFile, "# Object files:\n");
                        fprintf(mapFile, "[%3u] %s\n", 0, "linker synthesized");
-                       uint32_t fileIndex = 0;
-                       readerToFileOrdinal[NULL] = fileIndex++;
-                       for(std::map<uint32_t, const ld::File*>::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) {
-                               if ( it->first != 0 ) {
-                                       fprintf(mapFile, "[%3u] %s\n", fileIndex, it->second->path());
-                                       readerToFileOrdinal[it->second] = fileIndex++;
-                               }
+                       uint32_t fileIndex = 1;
+                       for(std::map<ld::File::Ordinal, const ld::File*>::iterator it = ordinalToReader.begin(); it != ordinalToReader.end(); ++it) {
+                               fprintf(mapFile, "[%3u] %s\n", fileIndex, it->second->path());
+                               readerToFileOrdinal[it->second] = fileIndex++;
                        }
                        // write table of sections
                        fprintf(mapFile, "# Sections:\n");
@@ -3159,6 +4805,9 @@ void OutputFile::writeMapFile(ld::Internal& state)
                                        char buffer[4096];
                                        const ld::Atom* atom = *ait;
                                        const char* name = atom->name();
+                                       // don't add auto-stripped aliases to .map file
+                                       if ( (atom->size() == 0) && (atom->symbolTableInclusion() == ld::Atom::symbolTableNotInFinalLinkedImages) )
+                                               continue;
                                        if ( atom->contentType() == ld::Atom::typeCString ) {
                                                strcpy(buffer, "literal string: ");
                                                strlcat(buffer, (char*)atom->rawContentPointer(), 4096);
@@ -3167,8 +4816,8 @@ void OutputFile::writeMapFile(ld::Internal& state)
                                        else if ( (atom->contentType() == ld::Atom::typeCFI) && (strcmp(name, "FDE") == 0) ) {
                                                for (ld::Fixup::iterator fit = atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
                                                        if ( (fit->kind == ld::Fixup::kindSetTargetAddress) && (fit->clusterSize == ld::Fixup::k1of4) ) {
-                                                               assert(fit->binding == ld::Fixup::bindingDirectlyBound);
-                                                               if ( fit->u.target->section().type() == ld::Section::typeCode) {
+                                                               if ( (fit->binding == ld::Fixup::bindingDirectlyBound)
+                                                                &&  (fit->u.target->section().type() == ld::Section::typeCode) ) {
                                                                        strcpy(buffer, "FDE for: ");
                                                                        strlcat(buffer, fit->u.target->name(), 4096);
                                                                        name = buffer;
@@ -3204,7 +4853,6 @@ void OutputFile::writeMapFile(ld::Internal& state)
        }
 }
 
-
 // used to sort atoms with debug notes
 class DebugNoteSorter
 {
@@ -3212,25 +4860,19 @@ public:
        bool operator()(const ld::Atom* left, const ld::Atom* right) const
        {
                // first sort by reader
-               uint32_t leftFileOrdinal  = left->file()->ordinal();
-               uint32_t rightFileOrdinal = right->file()->ordinal();
+               ld::File::Ordinal leftFileOrdinal  = left->file()->ordinal();
+               ld::File::Ordinal rightFileOrdinal = right->file()->ordinal();
                if ( leftFileOrdinal!= rightFileOrdinal)
                        return (leftFileOrdinal < rightFileOrdinal);
 
                // then sort by atom objectAddress
-               uint64_t leftAddr  = left->objectAddress();
-               uint64_t rightAddr = right->objectAddress();
+               uint64_t leftAddr  = left->finalAddress();
+               uint64_t rightAddr = right->finalAddress();
                return leftAddr < rightAddr;
        }
 };
 
 
-class CStringEquals
-{
-public:
-       bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
-};
-
 const char* OutputFile::assureFullPath(const char* path)
 {
        if ( path[0] == '/' )
@@ -3245,6 +4887,15 @@ const char* OutputFile::assureFullPath(const char* path)
        return path;
 }
 
+static time_t fileModTime(const char* path) {
+       struct stat statBuffer;
+       if ( stat(path, &statBuffer) == 0 ) {
+               return statBuffer.st_mtime;
+       }
+       return 0;
+}
+
+
 void OutputFile::synthesizeDebugNotes(ld::Internal& state)
 {
        // -S means don't synthesize debug map
@@ -3266,12 +4917,20 @@ void OutputFile::synthesizeDebugNotes(ld::Internal& state)
                                continue;
                        if ( atom->symbolTableInclusion() == ld::Atom::symbolTableNotInFinalLinkedImages )
                                continue;
+                       if ( atom->symbolTableInclusion() == ld::Atom::symbolTableInWithRandomAutoStripLabel )
+                               continue;
                        // no stabs for absolute symbols
                        if ( atom->definition() == ld::Atom::definitionAbsolute ) 
                                continue;
                        // no stabs for .eh atoms
                        if ( atom->contentType() == ld::Atom::typeCFI )
                                continue;
+                       // no stabs for string literal atoms
+                       if ( atom->contentType() == ld::Atom::typeCString )
+                               continue;
+                       // no stabs for kernel dtrace probes
+                       if ( (_options.outputKind() == Options::kStaticExecutable) && (strncmp(atom->name(), "__dtrace_probe$", 15) == 0) )
+                               continue;
                        const ld::File* file = atom->file();
                        if ( file != NULL ) {
                                if ( file != objFile ) {
@@ -3303,25 +4962,46 @@ void OutputFile::synthesizeDebugNotes(ld::Internal& state)
        // sort by file ordinal then atom ordinal
        std::sort(atomsNeedingDebugNotes.begin(), atomsNeedingDebugNotes.end(), DebugNoteSorter());
 
+       // <rdar://problem/17689030> Add -add_ast_path option to linker which add N_AST stab entry to output
+       const std::vector<const char*>& astPaths = _options.astFilePaths();
+       for (std::vector<const char*>::const_iterator it=astPaths.begin(); it != astPaths.end(); it++) {
+               const char* path = *it;
+               //  emit N_AST
+               ld::relocatable::File::Stab astStab;
+               astStab.atom    = NULL;
+               astStab.type    = N_AST;
+               astStab.other   = 0;
+               astStab.desc    = 0;
+               astStab.value   = fileModTime(path);
+               astStab.string  = path;
+               state.stabs.push_back(astStab);
+       }
+       
        // synthesize "debug notes" and add them to master stabs vector
        const char* dirPath = NULL;
        const char* filename = NULL;
        bool wroteStartSO = false;
        state.stabs.reserve(atomsNeedingDebugNotes.size()*4);
-       __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals>  seenFiles;
+       std::unordered_set<const char*, CStringHash, CStringEquals>  seenFiles;
        for (std::vector<const ld::Atom*>::iterator it=atomsNeedingDebugNotes.begin(); it != atomsNeedingDebugNotes.end(); it++) {
                const ld::Atom* atom = *it;
                const ld::File* atomFile = atom->file();
                const ld::relocatable::File* atomObjFile = dynamic_cast<const ld::relocatable::File*>(atomFile);
-               const char* newDirPath;
-               const char* newFilename;
-               //fprintf(stderr, "debug note for %s\n", atom->getDisplayName());
-               if ( atom->translationUnitSource(&newDirPath, &newFilename) ) {
+               //fprintf(stderr, "debug note for %s\n", atom->name());
+               const char* newPath = atom->translationUnitSource();
+               if ( newPath != NULL ) {
+                       const char* newDirPath;
+                       const char* newFilename;
+                       const char* lastSlash = strrchr(newPath, '/');
+                       if ( lastSlash == NULL ) 
+                               continue;
+                       newFilename = lastSlash+1;
+                       char* temp = strdup(newPath);
+                       newDirPath = temp;
+                       // gdb like directory SO's to end in '/', but dwarf DW_AT_comp_dir usually does not have trailing '/'
+                       temp[lastSlash-newPath+1] = '\0';
                        // need SO's whenever the translation unit source file changes
-                       if ( newFilename != filename ) {
-                               // gdb like directory SO's to end in '/', but dwarf DW_AT_comp_dir usually does not have trailing '/'
-                               if ( (newDirPath != NULL) && (strlen(newDirPath) > 1 ) && (newDirPath[strlen(newDirPath)-1] != '/') )
-                                       asprintf((char**)&newDirPath, "%s/", newDirPath);
+                       if ( (filename == NULL) || (strcmp(newFilename,filename) != 0) || (strcmp(newDirPath,dirPath) != 0)) {
                                if ( filename != NULL ) {
                                        // translation unit change, emit ending SO
                                        ld::relocatable::File::Stab endFileStab;
@@ -3370,7 +5050,7 @@ void OutputFile::synthesizeDebugNotes(ld::Internal& state)
                                // add the source file path to seenFiles so it does not show up in SOLs
                                seenFiles.insert(newFilename);
                                char* fullFilePath;
-                               asprintf(&fullFilePath, "%s/%s", newDirPath, newFilename);
+                               asprintf(&fullFilePath, "%s%s", newDirPath, newFilename);
                                // add both leaf path and full path
                                seenFiles.insert(fullFilePath);
                        }
@@ -3494,7 +5174,7 @@ void OutputFile::synthesizeDebugNotes(ld::Internal& state)
                        }
                }
        }
-       
+
 }