]> git.saurik.com Git - apple/ld64.git/blobdiff - src/ld/OutputFile.cpp
ld64-134.9.tar.gz
[apple/ld64.git] / src / ld / OutputFile.cpp
index bb368c280ffa14172855648e3fb9f963817143ff..0f1153615a04d6b7cb57ef53d5ae2496423e711e 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@
  *
@@ -72,11 +72,12 @@ namespace tool {
 OutputFile::OutputFile(const Options& opts) 
        :
                hasWeakExternalSymbols(false), usesWeakExternalSymbols(false), overridesWeakExternalSymbols(false), 
-               _noReExportedDylibs(false), hasThreadLocalVariableDefinitions(false), pieDisabled(false), 
+               _noReExportedDylibs(false), hasThreadLocalVariableDefinitions(false), pieDisabled(false), hasDataInCode(false), 
                headerAndLoadCommandsSection(NULL),
                rebaseSection(NULL), bindingSection(NULL), weakBindingSection(NULL), 
                lazyBindingSection(NULL), exportSection(NULL), 
                splitSegInfoSection(NULL), functionStartsSection(NULL), 
+               dataInCodeSection(NULL), dependentDRsSection(NULL), 
                symbolTableSection(NULL), stringPoolSection(NULL), 
                localRelocationsSection(NULL), externalRelocationsSection(NULL), 
                sectionRelocationsSection(NULL), 
@@ -87,6 +88,8 @@ OutputFile::OutputFile(const Options& opts)
                _hasSectionRelocations(opts.outputKind() == Options::kObjectFile),
                _hasSplitSegInfo(opts.sharedRegionEligible()),
                _hasFunctionStartsInfo(opts.addFunctionStarts()),
+               _hasDataInCodeInfo(opts.addDataInCodeInfo()),
+               _hasDependentDRInfo(opts.needsDependentDRInfo()),
                _hasDynamicSymbolTable(true),
                _hasLocalRelocations(!opts.makeCompressedDyldInfo()),
                _hasExternalRelocations(!opts.makeCompressedDyldInfo()),
@@ -109,7 +112,9 @@ OutputFile::OutputFile(const Options& opts)
                _weakBindingInfoAtom(NULL),
                _exportInfoAtom(NULL),
                _splitSegInfoAtom(NULL),
-               _functionStartsAtom(NULL)
+               _functionStartsAtom(NULL),
+               _dataInCodeAtom(NULL),
+               _dependentDRInfoAtom(NULL)
 {
 }
 
@@ -179,10 +184,14 @@ bool OutputFile::findSegment(ld::Internal& state, uint64_t addr, uint64_t* start
 
 void OutputFile::assignAtomAddresses(ld::Internal& state)
 {
+       const bool log = false;
+       if ( log ) fprintf(stderr, "assignAtomAddresses()\n");
        for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
                ld::Internal::FinalSection* sect = *sit;
+               if ( log ) fprintf(stderr, "  section=%s/%s\n", sect->segmentName(), sect->sectionName());
                for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
                        const ld::Atom* atom = *ait;
+                       if ( log ) fprintf(stderr, "    atom=%p, name=%s\n", atom, atom->name());
                        switch ( sect-> type() ) {
                                case ld::Section::typeImportProxies:
                                        // want finalAddress() of all proxy atoms to be zero
@@ -239,6 +248,18 @@ void OutputFile::updateLINKEDITAddresses(ld::Internal& state)
                _functionStartsAtom->encode();
        }
 
+       if ( _options.addDataInCodeInfo() ) {
+               // build data-in-code info  
+               assert(_dataInCodeAtom != NULL);
+               _dataInCodeAtom->encode();
+       }
+       
+       if ( _options.needsDependentDRInfo() ) {
+               // build dependent dylib DR info  
+               assert(_dependentDRInfoAtom != NULL);
+               _dependentDRInfoAtom->encode();
+       }
+
        // build classic symbol table  
        assert(_symbolTableAtom != NULL);
        _symbolTableAtom->encode();
@@ -320,10 +341,25 @@ void OutputFile::setSectionSizesAndAlignments(ld::Internal& state)
                        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;
+                               bool pagePerAtom = false;
+                               uint32_t atomAlignmentPowerOf2 = atom->alignment().powerOf2;
+                               if ( _options.pageAlignDataAtoms() && ( strcmp(atom->section().segmentName(), "__DATA") == 0) ) { 
+                                       switch ( atom->section().type() ) {
+                                               case ld::Section::typeUnclassified:
+                                               case ld::Section::typeTentativeDefs:
+                                               case ld::Section::typeZeroFill:
+                                                       pagePerAtom = true;
+                                                       if ( atomAlignmentPowerOf2 < 12 )
+                                                               atomAlignmentPowerOf2 = 12;
+                                                       break;
+                                               default:
+                                                       break;
+                                       }
+                               }
+                               if ( atomAlignmentPowerOf2 > maxAlignment )
+                                       maxAlignment = atomAlignmentPowerOf2;
                                // calculate section offset for this atom
-                               uint64_t alignment = 1 << atom->alignment().powerOf2;
+                               uint64_t alignment = 1 << atomAlignmentPowerOf2;
                                uint64_t currentModulus = (offset % alignment);
                                uint64_t requiredModulus = atom->alignment().modulus;
                                if ( currentModulus != requiredModulus ) {
@@ -336,6 +372,9 @@ void OutputFile::setSectionSizesAndAlignments(ld::Internal& state)
                                if ( sect->type() != ld::Section::typeLinkEdit ) {
                                        (const_cast<ld::Atom*>(atom))->setSectionOffset(offset);
                                        offset += atom->size();
+                                       if ( pagePerAtom ) {
+                                               offset = (offset + 4095) & (-4096); // round up to end of page
+                                       }
                                }
                                if ( (atom->scope() == ld::Atom::scopeGlobal) 
                                        && (atom->definition() == ld::Atom::definitionRegular) 
@@ -498,6 +537,8 @@ void OutputFile::assignFileOffsets(ld::Internal& state)
        // second pass, assign section address to sections in segments that are contiguous with previous segment
        address = floatingAddressStart;
        lastSegName = "";
+       ld::Internal::FinalSection* overlappingFixedSection = NULL;
+       ld::Internal::FinalSection* overlappingFlowSection = NULL;
        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;
@@ -532,14 +573,48 @@ void OutputFile::assignFileOffsets(ld::Internal& state)
                                                                                                                          && (_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);
+
+               // sanity check it does not overlap a fixed address segment
+               for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+                       ld::Internal::FinalSection* otherSect = *sit;
+                       if ( ! _options.hasCustomSegmentAddress(otherSect->segmentName()) ) 
+                               continue;
+                       if ( sect->address > otherSect->address ) {
+                               if ( (otherSect->address+otherSect->size) > sect->address ) {
+                                       overlappingFixedSection = otherSect;
+                                       overlappingFlowSection = sect;
+                               }
+                       }
+                       else {
+                               if ( (sect->address+sect->size) > otherSect->address ) {
+                                       overlappingFixedSection = otherSect;
+                                       overlappingFlowSection = sect;
+                               }
+                       }
+               }
                
-               if ( log ) fprintf(stderr, "  address=0x%08llX, hidden=%d, alignment=%02d, padBytes=%d, section=%s,%s\n",
-                                                       sect->address, sect->isSectionHidden(), sect->alignment, sect->alignmentPaddingBytes, 
+               if ( log ) fprintf(stderr, "  address=0x%08llX, size=0x%08llX, hidden=%d, alignment=%02d, padBytes=%d, section=%s,%s\n",
+                                                       sect->address, sect->size, sect->isSectionHidden(), sect->alignment, sect->alignmentPaddingBytes, 
                                                        sect->segmentName(), sect->sectionName());
                // update running totals
                if ( !sect->isSectionHidden() || hiddenSectionsOccupyAddressSpace )
                        address += sect->size;
        }
+       if ( overlappingFixedSection != NULL ) {
+               fprintf(stderr, "Section layout:\n");
+               for (std::vector<ld::Internal::FinalSection*>::iterator it = state.sections.begin(); it != state.sections.end(); ++it) {
+                       ld::Internal::FinalSection* sect = *it;
+                       if ( sect->isSectionHidden() )
+                               continue;
+                       fprintf(stderr, "  address:0x%08llX, alignment:2^%d, size:0x%08llX, padBytes:%d, section:%s/%s\n",
+                                                       sect->address, sect->alignment, sect->size, sect->alignmentPaddingBytes, 
+                                                       sect->segmentName(), sect->sectionName());
+       
+               }
+               throwf("Section (%s/%s) overlaps fixed address section (%s/%s)", 
+                       overlappingFlowSection->segmentName(), overlappingFlowSection->sectionName(),
+                       overlappingFixedSection->segmentName(), overlappingFixedSection->sectionName());
+       }
        
        
        // third pass, assign section file offsets 
@@ -551,6 +626,9 @@ void OutputFile::assignFileOffsets(ld::Internal& state)
                if ( hasZeroForFileOffset(sect) ) {
                        // fileoff of zerofill sections is moot, but historically it is set to zero
                        sect->fileOffset = 0;
+
+                       // <rdar://problem/10445047> align file offset with address layout
+                       fileOffset += sect->alignmentPaddingBytes;
                }
                else {
                        // page align file offset at start of each segment
@@ -581,7 +659,7 @@ void OutputFile::assignFileOffsets(ld::Internal& state)
                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);
+                               _encryptedTEXTendOffset = pageAlign(sect->fileOffset + sect->size);
                        }
                }
        }
@@ -659,6 +737,11 @@ uint64_t OutputFile::addressOf(const ld::Internal& state, const ld::Fixup* fixup
                        return (*target)->finalAddress();
                case ld::Fixup::bindingsIndirectlyBound:
                        *target = state.indirectBindingTable[fixup->u.bindingIndex];
+               #ifndef NDEBUG
+                       if ( ! (*target)->finalAddressMode() ) {
+                               throwf("reference to symbol (which has not been assigned an address) %s", (*target)->name());
+                       }
+               #endif
                        return (*target)->finalAddress();
        }
        throw "unexpected binding";
@@ -773,16 +856,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
+                       if ( _options.outputKind() != Options::kPreload ) {
+                               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);
                
@@ -822,8 +938,8 @@ void OutputFile::rangeCheckARMBranch24(int64_t displacement, ld::Internal& state
 
 void OutputFile::rangeCheckThumbBranch22(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
 {
-       // armv7 supports a larger displacement
-       if ( _options.preferSubArchitecture() && (_options.subArchitecture() == CPU_SUBTYPE_ARM_V7) ) {
+       // thumb2 supports a larger displacement
+       if ( _options.preferSubArchitecture() && _options.archSupportsThumb2() ) {
                if ( (displacement > 16777214LL) || (displacement < (-16777216LL)) ) {
                        // show layout of final image
                        printSectionLayout(state);
@@ -847,33 +963,6 @@ void OutputFile::rangeCheckThumbBranch22(int64_t displacement, ld::Internal& sta
        }
 }
 
-void OutputFile::rangeCheckPPCBranch24(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
-{
-       const int64_t bl_eightMegLimit = 0x00FFFFFF;
-       if ( (displacement > bl_eightMegLimit) || (displacement < (-bl_eightMegLimit)) ) {
-               // show layout of final image
-               printSectionLayout(state);
-               
-               const ld::Atom* target; 
-               throwf("bl PPC branch out of range (%lld max is +/-16MB): from %s (0x%08llX) to %s (0x%08llX)", 
-                               displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup), 
-                               addressOf(state, fixup, &target));
-       }
-}
-
-void OutputFile::rangeCheckPPCBranch14(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
-{
-       const int64_t b_sixtyFourKiloLimit = 0x0000FFFF;
-       if ( (displacement > b_sixtyFourKiloLimit) || (displacement < (-b_sixtyFourKiloLimit)) ) {
-               // show layout of final image
-               printSectionLayout(state);
-               
-               const ld::Atom* target; 
-               throwf("bcc PPC branch out of range (%lld max is +/-64KB): from %s (0x%08llX) to %s (0x%08llX)", 
-                               displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup), 
-                               addressOf(state, fixup, &target));
-       }
-}
 
 
 
@@ -905,7 +994,6 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
        int64_t delta;
        uint32_t instruction;
        uint32_t newInstruction;
-       uint16_t instructionLowHalf;
        bool is_bl;
        bool is_blx;
        bool is_b;
@@ -967,6 +1055,7 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                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:
@@ -979,6 +1068,7 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                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:
@@ -1092,41 +1182,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 +1204,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
@@ -1191,6 +1234,13 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                assert(fit->binding == ld::Fixup::bindingDirectlyBound);
                                accumulator = this->lazyBindingInfoOffsetForLazyPointerAddress(fit->u.target->finalAddress());
                                break;
+                       case ld::Fixup::kindDataInCodeStartData:
+                       case ld::Fixup::kindDataInCodeStartJT8:
+                       case ld::Fixup::kindDataInCodeStartJT16:
+                       case ld::Fixup::kindDataInCodeStartJT32:
+                       case ld::Fixup::kindDataInCodeStartJTA32:
+                       case ld::Fixup::kindDataInCodeEnd:
+                               break;
                        case ld::Fixup::kindStoreTargetAddressLittleEndian32:
                                accumulator = addressOf(state, fit, &toTarget);
                                thumbTarget = targetIsThumb(state, fit);
@@ -1198,6 +1248,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:
@@ -1287,6 +1338,7 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                // Make sure we are calling arm with bl, thumb with blx                 
                                is_bl = ((instruction & 0xFF000000) == 0xEB000000);
                                is_blx = ((instruction & 0xFE000000) == 0xFA000000);
+                               is_b = !is_blx && ((instruction & 0x0F000000) == 0x0A000000);
                                if ( is_bl && thumbTarget ) {
                                        uint32_t opcode = 0xFA000000;
                                        uint32_t disp = (uint32_t)(delta >> 2) & 0x00FFFFFF;
@@ -1298,6 +1350,13 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                        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));
@@ -1324,14 +1383,14 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                // 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 ) {
+                               if ( !thumbTarget && !fit->contentDetlaToAddendOnly ) {
                                  accumulator &= -3ULL;
                                  accumulator |= ((atom->finalAddress() + fit->offsetInAtom ) & 2LL);
                                }
                                // The pc added will be +4 from the pc
                                delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 4);
                                rangeCheckThumbBranch22(delta, state, atom, fit);
-                               if ( _options.preferSubArchitecture() && _options.subArchitecture() == CPU_SUBTYPE_ARM_V7 ) {
+                               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 +1416,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));
@@ -1389,10 +1449,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;
                                        }
@@ -1440,38 +1503,27 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                        set32LE(fixUpLocation, newInstruction);         
                                }
                                break;
-                       case ld::Fixup::kindStoreTargetAddressPPCBranch24:
-                               accumulator = addressOf(state, fit, &toTarget);
-                               if ( fit->contentDetlaToAddendOnly )
-                                       accumulator = 0;
-                               // fall into kindStorePPCBranch24 case
-                       case ld::Fixup::kindStorePPCBranch24:
-                               delta = accumulator - (atom->finalAddress() + fit->offsetInAtom);
-                               rangeCheckPPCBranch24(delta, state, atom, fit);
-                               instruction = get32BE(fixUpLocation);
-                               newInstruction = (instruction & 0xFC000003) | ((uint32_t)delta & 0x03FFFFFC);
-                               set32BE(fixUpLocation, newInstruction);
-                               break;
                }
        }
 }
 
-void OutputFile::copyNoOps(uint8_t* from, uint8_t* to)
+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 +1565,8 @@ bool OutputFile::hasZeroForFileOffset(const ld::Section* sect)
        return false;
 }
 
-
-void OutputFile::writeOutputFile(ld::Internal& state)
+void OutputFile::writeAtoms(ld::Internal& state, uint8_t* wholeBuffer)
 {
-       // for UNIX conformance, error if file exists and is not writable
-       if ( (access(_options.outputFilePath(), F_OK) == 0) && (access(_options.outputFilePath(), W_OK) == -1) )
-               throwf("can't write output file: %s", _options.outputFilePath());
-
-       int permissions = 0777;
-       if ( _options.outputKind() == Options::kObjectFile )
-               permissions = 0666;
-       // Calling unlink first assures the file is gone so that open creates it with correct permissions
-       // It also handles the case where __options.outputFilePath() file is not writable but its directory is
-       // And it means we don't have to truncate the file when done writing (in case new is smaller than old)
-       // Lastly, only delete existing file if it is a normal file (e.g. not /dev/null).
-       struct stat stat_buf;
-       if ( (stat(_options.outputFilePath(), &stat_buf) != -1) && (stat_buf.st_mode & S_IFREG) )
-               (void)unlink(_options.outputFilePath());
-
-       // try to allocate buffer for entire output file content
-       uint8_t* wholeBuffer = (uint8_t*)calloc(_fileSize, 1);
-       if ( wholeBuffer == NULL )
-               throwf("can't create buffer of %llu bytes for output", _fileSize);
-       
-       if ( _options.UUIDMode() == Options::kUUIDRandom ) {
-               uint8_t bits[16];
-               ::uuid_generate_random(bits);
-               _headersAndLoadCommandAtom->setUUID(bits);
-       }
-
        // have each atom write itself
        uint64_t fileOffsetOfEndOfLastAtom = 0;
        uint64_t mhAddress = 0;
@@ -1555,6 +1580,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 +1589,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,6 +1597,7 @@ 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 )
@@ -1580,74 +1607,153 @@ void OutputFile::writeOutputFile(ld::Internal& state)
                        }
                }
        }
-       
-       // 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;
-                                       }
+}
+
+
+void OutputFile::computeContentUUID(ld::Internal& state, uint8_t* wholeBuffer)
+{
+       const bool log = false;
+       if ( (_options.outputKind() != Options::kObjectFile) || state.someObjectFileHasDwarf ) {
+               uint8_t digest[CC_MD5_DIGEST_LENGTH];
+               uint32_t        stabsStringsOffsetStart;
+               uint32_t        tabsStringsOffsetEnd;
+               uint32_t        stabsOffsetStart;
+               uint32_t        stabsOffsetEnd;
+               if ( _symbolTableAtom->hasStabs(stabsStringsOffsetStart, tabsStringsOffsetEnd, stabsOffsetStart, stabsOffsetEnd) ) {
+                       // find two areas of file that are stabs info and should not contribute to checksum
+                       uint64_t stringPoolFileOffset = 0;
+                       uint64_t symbolTableFileOffset = 0;
+                       for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+                               ld::Internal::FinalSection* sect = *sit;
+                               if ( sect->type() == ld::Section::typeLinkEdit ) {
+                                       if ( strcmp(sect->sectionName(), "__string_pool") == 0 )
+                                               stringPoolFileOffset = sect->fileOffset;
+                                       else if ( strcmp(sect->sectionName(), "__symbol_table") == 0 )
+                                               symbolTableFileOffset = sect->fileOffset;
                                }
-                               uint64_t firstStabNlistFileOffset  = symbolTableFileOffset + stabsOffsetStart;
-                               uint64_t lastStabNlistFileOffset   = symbolTableFileOffset + stabsOffsetEnd;
-                               uint64_t firstStabStringFileOffset = stringPoolFileOffset  + stabsStringsOffsetStart;
-                               uint64_t lastStabStringFileOffset  = stringPoolFileOffset  + tabsStringsOffsetEnd;
-                               if ( log ) fprintf(stderr, "firstStabNlistFileOffset=0x%08llX\n", firstStabNlistFileOffset);
-                               if ( log ) fprintf(stderr, "lastStabNlistFileOffset=0x%08llX\n", lastStabNlistFileOffset);
-                               if ( log ) fprintf(stderr, "firstStabStringFileOffset=0x%08llX\n", firstStabStringFileOffset);
-                               if ( log ) fprintf(stderr, "lastStabStringFileOffset=0x%08llX\n", lastStabStringFileOffset);
-                               assert(firstStabNlistFileOffset <= firstStabStringFileOffset);
-                               
-                               CC_MD5_CTX md5state;
-                               CC_MD5_Init(&md5state);
-                               // checksum everything up to first stabs nlist
-                               if ( log ) fprintf(stderr, "checksum 0x%08X -> 0x%08llX\n", 0, firstStabNlistFileOffset);
-                               CC_MD5_Update(&md5state, &wholeBuffer[0], firstStabNlistFileOffset);
-                               // checkusm everything after last stabs nlist and up to first stabs string
-                               if ( log ) fprintf(stderr, "checksum 0x%08llX -> 0x%08llX\n", lastStabNlistFileOffset, firstStabStringFileOffset);
-                               CC_MD5_Update(&md5state, &wholeBuffer[lastStabNlistFileOffset], firstStabStringFileOffset-lastStabNlistFileOffset);
-                               // checksum everything after last stabs string to end of file
-                               if ( log ) fprintf(stderr, "checksum 0x%08llX -> 0x%08llX\n", lastStabStringFileOffset, _fileSize);
-                               CC_MD5_Update(&md5state, &wholeBuffer[lastStabStringFileOffset], _fileSize-lastStabStringFileOffset);
-                               CC_MD5_Final(digest, &md5state);
-                               if ( log ) fprintf(stderr, "uuid=%02X, %02X, %02X, %02X, %02X, %02X, %02X, %02X\n", digest[0], digest[1], digest[2], 
-                                                                                                                                       digest[3], digest[4], digest[5], digest[6],  digest[7]);
                        }
-                       else {
-                               CC_MD5(wholeBuffer, _fileSize, digest);
-                       }
-                       // <rdar://problem/6723729> LC_UUID uuids should conform to RFC 4122 UUID version 4 & UUID version 5 formats
-                       digest[6] = ( digest[6] & 0x0F ) | ( 3 << 4 );
-                       digest[8] = ( digest[8] & 0x3F ) | 0x80;
-                       // update buffer with new UUID
-                       _headersAndLoadCommandAtom->setUUID(digest);
-                       _headersAndLoadCommandAtom->recopyUUIDCommand();
+                       uint64_t firstStabNlistFileOffset  = symbolTableFileOffset + stabsOffsetStart;
+                       uint64_t lastStabNlistFileOffset   = symbolTableFileOffset + stabsOffsetEnd;
+                       uint64_t firstStabStringFileOffset = stringPoolFileOffset  + stabsStringsOffsetStart;
+                       uint64_t lastStabStringFileOffset  = stringPoolFileOffset  + tabsStringsOffsetEnd;
+                       if ( log ) fprintf(stderr, "firstStabNlistFileOffset=0x%08llX\n", firstStabNlistFileOffset);
+                       if ( log ) fprintf(stderr, "lastStabNlistFileOffset=0x%08llX\n", lastStabNlistFileOffset);
+                       if ( log ) fprintf(stderr, "firstStabStringFileOffset=0x%08llX\n", firstStabStringFileOffset);
+                       if ( log ) fprintf(stderr, "lastStabStringFileOffset=0x%08llX\n", lastStabStringFileOffset);
+                       assert(firstStabNlistFileOffset <= firstStabStringFileOffset);
+                       
+                       CC_MD5_CTX md5state;
+                       CC_MD5_Init(&md5state);
+                       // checksum everything up to first stabs nlist
+                       if ( log ) fprintf(stderr, "checksum 0x%08X -> 0x%08llX\n", 0, firstStabNlistFileOffset);
+                       CC_MD5_Update(&md5state, &wholeBuffer[0], firstStabNlistFileOffset);
+                       // checkusm everything after last stabs nlist and up to first stabs string
+                       if ( log ) fprintf(stderr, "checksum 0x%08llX -> 0x%08llX\n", lastStabNlistFileOffset, firstStabStringFileOffset);
+                       CC_MD5_Update(&md5state, &wholeBuffer[lastStabNlistFileOffset], firstStabStringFileOffset-lastStabNlistFileOffset);
+                       // checksum everything after last stabs string to end of file
+                       if ( log ) fprintf(stderr, "checksum 0x%08llX -> 0x%08llX\n", lastStabStringFileOffset, _fileSize);
+                       CC_MD5_Update(&md5state, &wholeBuffer[lastStabStringFileOffset], _fileSize-lastStabStringFileOffset);
+                       CC_MD5_Final(digest, &md5state);
+                       if ( log ) fprintf(stderr, "uuid=%02X, %02X, %02X, %02X, %02X, %02X, %02X, %02X\n", digest[0], digest[1], digest[2], 
+                                                          digest[3], digest[4], digest[5], digest[6],  digest[7]);
+               }
+               else {
+                       CC_MD5(wholeBuffer, _fileSize, digest);
+               }
+               // <rdar://problem/6723729> LC_UUID uuids should conform to RFC 4122 UUID version 4 & UUID version 5 formats
+               digest[6] = ( digest[6] & 0x0F ) | ( 3 << 4 );
+               digest[8] = ( digest[8] & 0x3F ) | 0x80;
+               // update buffer with new UUID
+               _headersAndLoadCommandAtom->setUUID(digest);
+               _headersAndLoadCommandAtom->recopyUUIDCommand();
+       }
+}
+       
+       
+void OutputFile::writeOutputFile(ld::Internal& state)
+{
+       // for UNIX conformance, error if file exists and is not writable
+       if ( (access(_options.outputFilePath(), F_OK) == 0) && (access(_options.outputFilePath(), W_OK) == -1) )
+               throwf("can't write output file: %s", _options.outputFilePath());
+
+       mode_t permissions = 0777;
+       if ( _options.outputKind() == Options::kObjectFile )
+               permissions = 0666;
+       mode_t umask = ::umask(0);
+       ::umask(umask); // put back the original umask
+       permissions &= ~umask;
+       // Calling unlink first assures the file is gone so that open creates it with correct permissions
+       // It also handles the case where __options.outputFilePath() file is not writable but its directory is
+       // And it means we don't have to truncate the file when done writing (in case new is smaller than old)
+       // Lastly, only delete existing file if it is a normal file (e.g. not /dev/null).
+       struct stat stat_buf;
+       bool outputIsRegularFile = true;
+       if ( stat(_options.outputFilePath(), &stat_buf) != -1 ) {
+               if (stat_buf.st_mode & S_IFREG) {
+                       (void)unlink(_options.outputFilePath());
+               } else {
+                       outputIsRegularFile = false;
+               }
+       }
+
+       int fd;
+       // Construct a temporary path of the form {outputFilePath}.ld_XXXXXX
+       const char filenameTemplate[] = ".ld_XXXXXX";
+       char tmpOutput[PATH_MAX];
+       uint8_t *wholeBuffer;
+       if (outputIsRegularFile) {
+               strcpy(tmpOutput, _options.outputFilePath());
+               // If the path is too long to add a suffix for a temporary name then
+               // just fall back to using the output path. 
+               if (strlen(tmpOutput)+strlen(filenameTemplate) < PATH_MAX) {
+                       strcat(tmpOutput, filenameTemplate);
+                       fd = mkstemp(tmpOutput);
+               } else {
+                       fd = open(tmpOutput, O_RDWR|O_CREAT, permissions);
                }
+               if ( fd == -1 ) 
+                       throwf("can't open output file for writing: %s, errno=%d", tmpOutput, errno);
+               ftruncate(fd, _fileSize);
+               
+               wholeBuffer = (uint8_t *)mmap(NULL, _fileSize, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0);
+               if ( wholeBuffer == MAP_FAILED )
+                       throwf("can't create buffer of %llu bytes for output", _fileSize);
+       } else {
+               fd = open(_options.outputFilePath(), O_WRONLY);
+               if ( fd == -1 ) 
+                       throwf("can't open output file for writing: %s, errno=%d", _options.outputFilePath(), errno);
+               // try to allocate buffer for entire output file content
+               wholeBuffer = (uint8_t*)calloc(_fileSize, 1);
+               if ( wholeBuffer == NULL )
+                       throwf("can't create buffer of %llu bytes for output", _fileSize);
+       }
+       
+       if ( _options.UUIDMode() == Options::kUUIDRandom ) {
+               uint8_t bits[16];
+               ::uuid_generate_random(bits);
+               _headersAndLoadCommandAtom->setUUID(bits);
        }
 
-       // write whole output file in one chunk
-       int fd = open(_options.outputFilePath(), O_CREAT | O_WRONLY | O_TRUNC, permissions);
-       if ( fd == -1 ) 
-               throwf("can't open output file for writing: %s, errno=%d", _options.outputFilePath(), errno);
-       if ( ::pwrite(fd, wholeBuffer, _fileSize, 0) == -1 )
-               throwf("can't write to output file: %s, errno=%d", _options.outputFilePath(), errno);
-       close(fd);
-       free(wholeBuffer);
+       writeAtoms(state, wholeBuffer);
+       
+       // compute UUID 
+       if ( _options.UUIDMode() == Options::kUUIDContent )
+               computeContentUUID(state, wholeBuffer);
+
+       if (outputIsRegularFile) {
+               if ( ::chmod(tmpOutput, permissions) == -1 ) {
+                       unlink(tmpOutput);
+                       throwf("can't set permissions on output file: %s, errno=%d", tmpOutput, errno);
+               }
+               if ( ::rename(tmpOutput, _options.outputFilePath()) == -1 && strcmp(tmpOutput, _options.outputFilePath()) != 0) {
+                       unlink(tmpOutput);
+                       throwf("can't move output file in place, errno=%d", errno);
+               }
+       } else {
+               if ( ::write(fd, wholeBuffer, _fileSize) == -1 ) {
+                       throwf("can't write to output file: %s, errno=%d", _options.outputFilePath(), errno);
+               }
+       }
 }
 
 struct AtomByNameSorter
@@ -1658,6 +1764,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;
@@ -1747,27 +1866,6 @@ void OutputFile::buildSymbolTable(ld::Internal& state)
                                continue;
                        }
                        
-                       // <rdar://problem/7977374> Add command line options to control symbol weak-def bit on exported symbols                 
-                       if ( _options.hasWeakBitTweaks() && (atom->definition() == ld::Atom::definitionRegular) ) {
-                               const char* name = atom->name();
-                               if ( atom->scope() == ld::Atom::scopeGlobal ) {
-                                       if ( atom->combine() == ld::Atom::combineNever ) {
-                                               if ( _options.forceWeak(name) )
-                                                       (const_cast<ld::Atom*>(atom))->setCombine(ld::Atom::combineByName);
-                                       }
-                                       else if ( atom->combine() == ld::Atom::combineByName ) {
-                                               if ( _options.forceNotWeak(name) )
-                                                       (const_cast<ld::Atom*>(atom))->setCombine(ld::Atom::combineNever);
-                                       }
-                               }
-                               else {
-                                       if ( _options.forceWeakNonWildCard(name) )
-                                               warning("cannot force to be weak, non-external symbol %s", name);
-                                       else if ( _options.forceNotWeakNonWildcard(name) )
-                                               warning("cannot force to be not-weak, non-external symbol %s", name);
-                               }
-                       }
-                       
                        switch ( atom->scope() ) {
                                case ld::Atom::scopeTranslationUnit:
                                        if ( _options.keepLocalSymbol(atom->name()) ) { 
@@ -1800,7 +1898,11 @@ 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);
@@ -1810,15 +1912,41 @@ void OutputFile::buildSymbolTable(ld::Internal& state)
                }
        }
        
+       // <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 +1965,8 @@ void OutputFile::addPreloadLinkEdit(ld::Internal& state)
                                stringPoolSection = state.addAtom(*_stringPoolAtom);
                        }
                        break;
+#endif
+#if SUPPORT_ARCH_x86_64
                case CPU_TYPE_X86_64:
                        if ( _hasLocalRelocations ) {
                                _localRelocsAtom = new LocalRelocationsAtom<x86_64>(_options, state, *this);
@@ -1855,6 +1985,8 @@ void OutputFile::addPreloadLinkEdit(ld::Internal& state)
                                stringPoolSection = state.addAtom(*_stringPoolAtom);
                        }
                        break;
+#endif
+#if SUPPORT_ARCH_arm_any
                case CPU_TYPE_ARM:
                        if ( _hasLocalRelocations ) {
                                _localRelocsAtom = new LocalRelocationsAtom<arm>(_options, state, *this);
@@ -1873,6 +2005,7 @@ void OutputFile::addPreloadLinkEdit(ld::Internal& state)
                                stringPoolSection = state.addAtom(*_stringPoolAtom);
                        }
                        break;
+#endif
                default:
                        throw "architecture not supported for -preload";
        }
@@ -1887,54 +2020,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);
@@ -1968,6 +2054,14 @@ void OutputFile::addLinkEdit(ld::Internal& state)
                                _functionStartsAtom = new FunctionStartsAtom<x86>(_options, state, *this);
                                functionStartsSection = state.addAtom(*_functionStartsAtom);
                        }
+                       if ( _hasDataInCodeInfo ) {
+                               _dataInCodeAtom = new DataInCodeAtom<x86>(_options, state, *this);
+                               dataInCodeSection = state.addAtom(*_dataInCodeAtom);
+                       }
+                       if ( _hasDependentDRInfo ) {
+                               _dependentDRInfoAtom = new DependentDRAtom<x86>(_options, state, *this);
+                               dependentDRsSection = state.addAtom(*_dependentDRInfoAtom);
+                       }
                        if ( _hasSymbolTable ) {
                                _symbolTableAtom = new SymbolTableAtom<x86>(_options, state, *this);
                                symbolTableSection = state.addAtom(*_symbolTableAtom);
@@ -1983,6 +2077,8 @@ void OutputFile::addLinkEdit(ld::Internal& state)
                                stringPoolSection = state.addAtom(*_stringPoolAtom);
                        }
                        break;
+#endif
+#if SUPPORT_ARCH_x86_64
                case CPU_TYPE_X86_64:
                        if ( _hasSectionRelocations ) {
                                _sectionsRelocationsAtom = new SectionRelocationsAtom<x86_64>(_options, state, *this);
@@ -2016,6 +2112,14 @@ void OutputFile::addLinkEdit(ld::Internal& state)
                                _functionStartsAtom = new FunctionStartsAtom<x86_64>(_options, state, *this);
                                functionStartsSection = state.addAtom(*_functionStartsAtom);
                        }
+                       if ( _hasDataInCodeInfo ) {
+                               _dataInCodeAtom = new DataInCodeAtom<x86_64>(_options, state, *this);
+                               dataInCodeSection = state.addAtom(*_dataInCodeAtom);
+                       }
+                       if ( _hasDependentDRInfo ) {
+                               _dependentDRInfoAtom = new DependentDRAtom<x86_64>(_options, state, *this);
+                               dependentDRsSection = state.addAtom(*_dependentDRInfoAtom);
+                       }
                        if ( _hasSymbolTable ) {
                                _symbolTableAtom = new SymbolTableAtom<x86_64>(_options, state, *this);
                                symbolTableSection = state.addAtom(*_symbolTableAtom);
@@ -2031,6 +2135,8 @@ void OutputFile::addLinkEdit(ld::Internal& state)
                                stringPoolSection = state.addAtom(*_stringPoolAtom);
                        }
                        break;
+#endif
+#if SUPPORT_ARCH_arm_any
                case CPU_TYPE_ARM:
                        if ( _hasSectionRelocations ) {
                                _sectionsRelocationsAtom = new SectionRelocationsAtom<arm>(_options, state, *this);
@@ -2064,6 +2170,14 @@ void OutputFile::addLinkEdit(ld::Internal& state)
                                _functionStartsAtom = new FunctionStartsAtom<arm>(_options, state, *this);
                                functionStartsSection = state.addAtom(*_functionStartsAtom);
                        }
+                       if ( _hasDataInCodeInfo ) {
+                               _dataInCodeAtom = new DataInCodeAtom<arm>(_options, state, *this);
+                               dataInCodeSection = state.addAtom(*_dataInCodeAtom);
+                       }
+                       if ( _hasDependentDRInfo ) {
+                               _dependentDRInfoAtom = new DependentDRAtom<arm>(_options, state, *this);
+                               dependentDRsSection = state.addAtom(*_dependentDRInfoAtom);
+                       }
                        if ( _hasSymbolTable ) {
                                _symbolTableAtom = new SymbolTableAtom<arm>(_options, state, *this);
                                symbolTableSection = state.addAtom(*_symbolTableAtom);
@@ -2079,54 +2193,7 @@ void OutputFile::addLinkEdit(ld::Internal& state)
                                stringPoolSection = state.addAtom(*_stringPoolAtom);
                        }
                        break;
-               case CPU_TYPE_POWERPC64:
-                       if ( _hasSectionRelocations ) {
-                               _sectionsRelocationsAtom = new SectionRelocationsAtom<ppc64>(_options, state, *this);
-                               sectionRelocationsSection = state.addAtom(*_sectionsRelocationsAtom);
-                       }
-                       if ( _hasDyldInfo ) {
-                               _rebasingInfoAtom = new RebaseInfoAtom<ppc64>(_options, state, *this);
-                               rebaseSection = state.addAtom(*_rebasingInfoAtom);
-                               
-                               _bindingInfoAtom = new BindingInfoAtom<ppc64>(_options, state, *this);
-                               bindingSection = state.addAtom(*_bindingInfoAtom);
-                               
-                               _weakBindingInfoAtom = new WeakBindingInfoAtom<ppc64>(_options, state, *this);
-                               weakBindingSection = state.addAtom(*_weakBindingInfoAtom);
-                               
-                               _lazyBindingInfoAtom = new LazyBindingInfoAtom<ppc64>(_options, state, *this);
-                               lazyBindingSection = state.addAtom(*_lazyBindingInfoAtom);
-                               
-                               _exportInfoAtom = new ExportInfoAtom<ppc64>(_options, state, *this);
-                               exportSection = state.addAtom(*_exportInfoAtom);
-                       }
-                       if ( _hasLocalRelocations ) {
-                               _localRelocsAtom = new LocalRelocationsAtom<ppc64>(_options, state, *this);
-                               localRelocationsSection = state.addAtom(*_localRelocsAtom);
-                       }
-                       if  ( _hasSplitSegInfo ) {
-                               _splitSegInfoAtom = new SplitSegInfoAtom<ppc64>(_options, state, *this);
-                               splitSegInfoSection = state.addAtom(*_splitSegInfoAtom);
-                       }
-                       if ( _hasFunctionStartsInfo ) {
-                               _functionStartsAtom = new FunctionStartsAtom<ppc64>(_options, state, *this);
-                               functionStartsSection = state.addAtom(*_functionStartsAtom);
-                       }
-                       if ( _hasSymbolTable ) {
-                               _symbolTableAtom = new SymbolTableAtom<ppc64>(_options, state, *this);
-                               symbolTableSection = state.addAtom(*_symbolTableAtom);
-                       }
-                       if ( _hasExternalRelocations ) {
-                               _externalRelocsAtom = new ExternalRelocationsAtom<ppc64>(_options, state, *this);
-                               externalRelocationsSection = state.addAtom(*_externalRelocsAtom);
-                       }
-                       if ( _hasSymbolTable ) {
-                               _indirectSymbolTableAtom = new IndirectSymbolTableAtom<ppc64>(_options, state, *this);
-                               indirectSymbolTableSection = state.addAtom(*_indirectSymbolTableAtom);
-                               _stringPoolAtom = new StringPoolAtom(_options, state, *this, 4);
-                               stringPoolSection = state.addAtom(*_stringPoolAtom);
-                       }
-                       break;
+#endif
                default:
                        throw "unknown architecture";
        }
@@ -2135,26 +2202,24 @@ void OutputFile::addLinkEdit(ld::Internal& state)
 void OutputFile::addLoadCommands(ld::Internal& state)
 {
        switch ( _options.architecture() ) {
+#if SUPPORT_ARCH_x86_64
                case CPU_TYPE_X86_64:
                        _headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom<x86_64>(_options, state, *this);
                        headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom);
                        break;
+#endif
+#if SUPPORT_ARCH_arm_any
                case CPU_TYPE_ARM:
                        _headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom<arm>(_options, state, *this);
                        headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom);
                        break;
+#endif
+#if SUPPORT_ARCH_i386
                case CPU_TYPE_I386:
                        _headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom<x86>(_options, state, *this);
                        headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom);
                        break;
-               case CPU_TYPE_POWERPC:
-                       _headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom<ppc>(_options, state, *this);
-                       headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom);
-                       break;
-               case CPU_TYPE_POWERPC64:
-                       _headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom<ppc64>(_options, state, *this);
-                       headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom);
-                       break;
+#endif
                default:
                        throw "unknown architecture";
        }
@@ -2310,18 +2375,12 @@ 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::kindStoreTargetAddressARMBranch24:
                case ld::Fixup::kindStoreTargetAddressThumbBranch22:
                case ld::Fixup::kindStoreTargetAddressARMLoad12:
-               case ld::Fixup::kindStoreTargetAddressPPCBranch24:
                        return true;
                case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
                        return (_options.outputKind() != Options::kKextBundle);
@@ -2367,10 +2426,11 @@ 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::kindStoreTargetAddressX86Abs32TLVLoad:
                case ld::Fixup::kindStoreTargetAddressARMBranch24:
                case ld::Fixup::kindStoreTargetAddressThumbBranch22:
                case ld::Fixup::kindStoreTargetAddressARMLoad12:
-               case ld::Fixup::kindStoreTargetAddressPPCBranch24:
                        return true;
                case ld::Fixup::kindStoreX86DtraceCallSiteNop:
                case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
@@ -2378,8 +2438,6 @@ bool OutputFile::setsTarget(ld::Fixup::Kind kind)
                case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear:
                case ld::Fixup::kindStoreThumbDtraceCallSiteNop:
                case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
-               case ld::Fixup::kindStorePPCDtraceCallSiteNop:
-               case ld::Fixup::kindStorePPCDtraceIsEnableSiteClear:
                        return (_options.outputKind() == Options::kObjectFile);
                default:
                        break;
@@ -2538,7 +2596,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) ) {
@@ -2583,7 +2649,8 @@ void OutputFile::noteTextReloc(const ld::Atom* atom, const ld::Atom* target)
                if ( _options.warnAboutTextRelocs() )
                        warning("text reloc in %s to %s", atom->name(), target->name());
        } 
-       else if ( _options.positionIndependentExecutable() && (_options.iphoneOSVersionMin() >= ld::iPhone4_3) ) {
+       else if ( _options.positionIndependentExecutable() && (_options.outputKind() == Options::kDynamicExecutable) 
+               && ((_options.iOSVersionMin() >= ld::iOS_4_3) || (_options.macosxVersionMin() >= ld::mac10_7)) ) {
                if ( ! this->pieDisabled ) {
                        warning("PIE disabled. Absolute addressing (perhaps -mdynamic-no-pic) not allowed in code signed PIE, "
                                "but used in %s from %s. " 
@@ -2592,8 +2659,11 @@ void OutputFile::noteTextReloc(const ld::Atom* atom, const ld::Atom* target)
                }
                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());
+               throwf("illegal text-relocation to %s in %s from %s in %s", target->name(), target->file()->path(), atom->name(), atom->file()->path());
        }
 }
 
@@ -2608,8 +2678,23 @@ 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;
+                               }
+                               // 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 +2708,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;
        }
@@ -2651,7 +2742,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;
 
@@ -2747,6 +2838,22 @@ void OutputFile::addDyldInfo(ld::Internal& state,  ld::Internal::FinalSection* s
                        sect->hasLocalRelocs = true;  // so dyld knows to change permissions on __TEXT segment
                        rebaseType = REBASE_TYPE_TEXT_ABSOLUTE32;
                }
+               if ( (addend != 0) && _options.sharedRegionEligible() ) {
+                       // make sure the addend does not cause the pointer to point outside the target's segment
+                       // if it does, update_dyld_shared_cache will not be able to put this dylib into the shared cache
+                       uint64_t targetAddress = target->finalAddress();
+                       for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+                               ld::Internal::FinalSection* sct = *sit;
+                               uint64_t sctEnd = (sct->address+sct->size);
+                               if ( (sct->address <= targetAddress) && (targetAddress < sctEnd) ) {
+                                       if ( (targetAddress+addend) > sctEnd ) {
+                                               warning("data symbol %s from %s has pointer to %s + 0x%08llX. "  
+                                                               "That large of an addend may disable %s from being put in the dyld shared cache.", 
+                                                               atom->name(), atom->file()->path(), target->name(), addend, _options.installPath() );
+                                       }
+                               }
+                       }
+               }
                _rebaseInfo.push_back(RebaseInfo(rebaseType, address));
        }
        if ( needsBinding ) {
@@ -2764,10 +2871,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 +2883,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 +2937,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:
@@ -2893,9 +2997,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,25 +3006,6 @@ 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 ( _options.outputKind() == Options::kKextBundle ) {
                                assert(target != NULL);
@@ -2933,6 +3015,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;
        }
@@ -2945,6 +3042,27 @@ bool OutputFile::useExternalSectionReloc(const ld::Atom* atom, const ld::Atom* t
                // x86_64 uses 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);
@@ -3001,7 +3119,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;
                        }
@@ -3035,27 +3161,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 +3194,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,15 +3202,30 @@ 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::kindStoreTargetAddressX86PCRel32:
                                        case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
                                        case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
+                    case ld::Fixup::kindStoreARMLow16:
+                    case ld::Fixup::kindStoreThumbLow16: 
                                                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;
                                }
@@ -3107,8 +3252,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 +3264,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 +3274,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");
@@ -3212,14 +3354,14 @@ 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;
        }
 };
@@ -3313,15 +3455,21 @@ void OutputFile::synthesizeDebugNotes(ld::Internal& state)
                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) ) {
                                if ( filename != NULL ) {
                                        // translation unit change, emit ending SO
                                        ld::relocatable::File::Stab endFileStab;
@@ -3370,7 +3518,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);
                        }