]> git.saurik.com Git - apple/ld64.git/blobdiff - src/ld/LinkEditClassic.hpp
ld64-278.4.tar.gz
[apple/ld64.git] / src / ld / LinkEditClassic.hpp
index d5438acddd6b4208039b895880490123d74c6b15..fd9098f15d76876793a45fb85f31ff9bfe756eba 100644 (file)
@@ -32,6 +32,7 @@
 #include <unistd.h>
 
 #include <vector>
+#include <unordered_map>
 
 #include "Options.h"
 #include "ld.hpp"
@@ -49,8 +50,6 @@ public:
 
        // overrides of ld::Atom
        virtual ld::File*                                                       file() const            { return NULL; }
-       virtual bool                                                            translationUnitSource(const char** dir, const char** nm) const
-                                                                                                                                       { return false; }
        virtual uint64_t                                                        objectAddress() const { return 0; }
 
        virtual void                                                            encode() = 0;
@@ -92,13 +91,8 @@ public:
        uint32_t                                                                        currentOffset();
 
 private:
-       class CStringEquals
-       {
-       public:
-               bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
-       };
        enum { kBufferSize = 0x01000000 };
-       typedef __gnu_cxx::hash_map<const char*, int32_t, __gnu_cxx::hash<const char*>, CStringEquals> StringToOffset;
+       typedef std::unordered_map<const char*, int32_t, CStringHash, CStringEquals> StringToOffset;
 
        const uint32_t                                                  _pointerSize;
        std::vector<char*>                                              _fullBuffers;
@@ -230,7 +224,7 @@ private:
        uint32_t                                                stringOffsetForStab(const ld::relocatable::File::Stab& stab, StringPoolAtom* pool);
        uint64_t                                                valueForStab(const ld::relocatable::File::Stab& stab);
        uint8_t                                                 sectionIndexForStab(const ld::relocatable::File::Stab& stab);
-       
+       bool                                                    isAltEntry(const ld::Atom* atom);
 
        mutable std::vector<macho_nlist<P> >    _globals;
        mutable std::vector<macho_nlist<P> >    _locals;
@@ -242,18 +236,44 @@ private:
        uint32_t                                                                _stabsIndexEnd;
 
        static ld::Section                      _s_section;
+       static int                                      _s_anonNameIndex;
+
 };
 
 template <typename A>
 ld::Section SymbolTableAtom<A>::_s_section("__LINKEDIT", "__symbol_table", ld::Section::typeLinkEdit, true);
 
+template <typename A>
+int     SymbolTableAtom<A>::_s_anonNameIndex = 1;
+
 
+template <typename A>
+bool SymbolTableAtom<A>::isAltEntry(const ld::Atom* atom) 
+{
+       // alt entries have a group subordinate reference to the previous atom
+       for (ld::Fixup::iterator fit = atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
+               if ( fit->kind == ld::Fixup::kindNoneGroupSubordinate ) {
+                       if ( fit->binding == Fixup::bindingDirectlyBound ) {
+                               const Atom* prevAtom = fit->u.target;
+                               assert(prevAtom != NULL);
+                               for (ld::Fixup::iterator fit2 = prevAtom->fixupsBegin(); fit2 != prevAtom->fixupsEnd(); ++fit2) {
+                                       if ( fit2->kind == ld::Fixup::kindNoneFollowOn ) {
+                                               if ( fit2->binding == Fixup::bindingDirectlyBound ) {
+                                                       if ( fit2->u.target == atom )
+                                                               return true;
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+       return false;
+}
 
 template <typename A>
 bool SymbolTableAtom<A>::addLocal(const ld::Atom* atom, StringPoolAtom* pool) 
 {
        macho_nlist<P> entry;
-       static int s_anonNameIndex = 1;
        assert(atom->symbolTableInclusion() != ld::Atom::symbolTableNotIn);
         
        // set n_strx
@@ -264,7 +284,7 @@ bool SymbolTableAtom<A>::addLocal(const ld::Atom* atom, StringPoolAtom* pool)
                        if ( atom->combine() == ld::Atom::combineByNameAndContent ) {
                                // don't use 'l' labels for x86_64 strings
                                // <rdar://problem/6605499> x86_64 obj-c runtime confused when static lib is stripped
-                               sprintf(anonName, "LC%u", s_anonNameIndex++);
+                               sprintf(anonName, "LC%u", _s_anonNameIndex++);
                                symbolName = anonName;
                        }
                }
@@ -279,7 +299,7 @@ bool SymbolTableAtom<A>::addLocal(const ld::Atom* atom, StringPoolAtom* pool)
                }
                else if ( atom->symbolTableInclusion() == ld::Atom::symbolTableInWithRandomAutoStripLabel ) {
                        // make auto-strip anonymous name for symbol 
-                       sprintf(anonName, "l%03u", s_anonNameIndex++);
+                       sprintf(anonName, "l%03u", _s_anonNameIndex++);
                        symbolName = anonName;
                }
        }
@@ -315,6 +335,8 @@ bool SymbolTableAtom<A>::addLocal(const ld::Atom* atom, StringPoolAtom* pool)
                desc |= N_WEAK_DEF;
        if ( atom->isThumb() )
                desc |= N_ARM_THUMB_DEF;
+    if ( (this->_options.outputKind() == Options::kObjectFile) && this->_state.allObjectFilesScatterable && isAltEntry(atom) )
+        desc |= N_ALT_ENTRY;
        entry.set_n_desc(desc);
 
        // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
@@ -335,7 +357,16 @@ void SymbolTableAtom<A>::addGlobal(const ld::Atom* atom, StringPoolAtom* pool)
        macho_nlist<P> entry;
 
        // set n_strx
-       entry.set_n_strx(pool->add(atom->name()));
+       const char* symbolName = atom->name();
+       char anonName[32];
+       if ( this->_options.outputKind() == Options::kObjectFile ) {
+               if ( atom->symbolTableInclusion() == ld::Atom::symbolTableInWithRandomAutoStripLabel ) {
+                       // make auto-strip anonymous name for symbol 
+                       sprintf(anonName, "l%03u", _s_anonNameIndex++);
+                       symbolName = anonName;
+               }
+       }
+       entry.set_n_strx(pool->add(symbolName));
 
        // set n_type
        if ( atom->definition() == ld::Atom::definitionAbsolute ) {
@@ -356,8 +387,9 @@ void SymbolTableAtom<A>::addGlobal(const ld::Atom* atom, StringPoolAtom* pool)
                                entry.set_n_type(N_EXT | N_SECT | N_PEXT);
                }
                else if ( (atom->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip)
-                                       && (atom->section().type() == ld::Section::typeMachHeader) ) {
-                       // the __mh_execute_header is historical magic and must be an absolute symbol
+                                       && (atom->section().type() == ld::Section::typeMachHeader) 
+                                       && !_options.positionIndependentExecutable() ) {
+                       // the __mh_execute_header is historical magic in non-pie executabls and must be an absolute symbol
                        entry.set_n_type(N_EXT | N_ABS);
                }
        }
@@ -380,6 +412,8 @@ void SymbolTableAtom<A>::addGlobal(const ld::Atom* atom, StringPoolAtom* pool)
         desc |= N_SYMBOL_RESOLVER;
     if ( atom->dontDeadStrip() && (this->_options.outputKind() == Options::kObjectFile) )
         desc |= N_NO_DEAD_STRIP;
+    if ( (this->_options.outputKind() == Options::kObjectFile) && this->_state.allObjectFilesScatterable && isAltEntry(atom) )
+        desc |= N_ALT_ENTRY;
        if ( (atom->definition() == ld::Atom::definitionRegular) && (atom->combine() == ld::Atom::combineByName) ) {
                desc |= N_WEAK_DEF;
                // <rdar://problem/6783167> support auto hidden weak symbols: .weak_def_can_be_hidden
@@ -444,7 +478,13 @@ void SymbolTableAtom<A>::addImport(const ld::Atom* atom, StringPoolAtom* pool)
 
        // set n_type
        if ( this->_options.outputKind() == Options::kObjectFile ) {
-               if ( (atom->scope() == ld::Atom::scopeLinkageUnit) 
+               if ( atom->section().type() == ld::Section::typeTempAlias ) {
+                       if ( atom->scope() == ld::Atom::scopeLinkageUnit )
+                               entry.set_n_type(N_INDR | N_EXT | N_PEXT);
+                       else
+                               entry.set_n_type(N_INDR | N_EXT);
+               }
+               else if ( (atom->scope() == ld::Atom::scopeLinkageUnit) 
                                && (atom->definition() == ld::Atom::definitionTentative) )
                        entry.set_n_type(N_UNDF | N_EXT | N_PEXT);
                else 
@@ -485,15 +525,32 @@ void SymbolTableAtom<A>::addImport(const ld::Atom* atom, StringPoolAtom* pool)
                && (atom->combine() == ld::Atom::combineByName) ) {
                        desc |= N_REF_TO_WEAK;
        }
-       if ( atom->weakImported() )     
+       const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(atom->file());
+       if ( atom->weakImported() || ((dylib != NULL) && dylib->forcedWeakLinked()) )
                desc |= N_WEAK_REF;
        entry.set_n_desc(desc);
 
        // set n_value, zero for import proxy and size for tentative definition
        if ( atom->definition() == ld::Atom::definitionTentative )
                entry.set_n_value(atom->size());
-       else
+       else if ( atom->section().type() != ld::Section::typeTempAlias )
                entry.set_n_value(0);
+       else {
+               assert(atom->fixupsBegin() != atom->fixupsEnd());
+               for (ld::Fixup::iterator fit = atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
+                       assert(fit->kind == ld::Fixup::kindNoneFollowOn);
+                       switch ( fit->binding ) {
+                               case ld::Fixup::bindingByNameUnbound:
+                                       entry.set_n_value(pool->add(fit->u.name));
+                                       break;
+                               case ld::Fixup::bindingsIndirectlyBound:
+                                       entry.set_n_value(pool->add((_state.indirectBindingTable[fit->u.bindingIndex])->name()));
+                                       break;
+                               default:
+                                       assert(0 && "internal error: unexpected alias binding");
+                       }
+               }
+       }
        
        // add to array
        _imports.push_back(entry);
@@ -608,42 +665,22 @@ bool SymbolTableAtom<A>::hasStabs(uint32_t& ssos, uint32_t& ssoe, uint32_t& sos,
        return ( (_stabsIndexStart != _stabsIndexEnd) || (_stabsStringsOffsetStart != _stabsStringsOffsetEnd) );
 }
 
+
 template <typename A>
 void SymbolTableAtom<A>::encode()
 {
-       uint32_t symbolIndex = 0;
+       // Note: We lay out the symbol table so that the strings for the stabs (local) symbols are at the
+       // end of the string pool.  The stabs strings are not used when calculated the UUID for the image.
+       // If the stabs strings were not last, the string offsets for all other symbols may very which would alter the UUID.
 
-       // make nlist entries for all local symbols
-       std::vector<const ld::Atom*>& localAtoms = this->_writer._localAtoms;
-       _locals.reserve(localAtoms.size()+this->_state.stabs.size());
-       this->_writer._localSymbolsStartIndex = 0;
-       // make nlist entries for all debug notes
-       _stabsIndexStart = symbolIndex;
-       _stabsStringsOffsetStart = this->_writer._stringPoolAtom->currentOffset();
-       for (std::vector<ld::relocatable::File::Stab>::const_iterator sit=this->_state.stabs.begin(); sit != this->_state.stabs.end(); ++sit) {
-               macho_nlist<P> entry;
-               entry.set_n_type(sit->type);
-               entry.set_n_sect(sectionIndexForStab(*sit));
-               entry.set_n_desc(sit->desc);
-               entry.set_n_value(valueForStab(*sit));
-               entry.set_n_strx(stringOffsetForStab(*sit, this->_writer._stringPoolAtom));
-               _locals.push_back(entry);
-               ++symbolIndex;
-       }
-       _stabsIndexEnd = symbolIndex;
-       _stabsStringsOffsetEnd = this->_writer._stringPoolAtom->currentOffset();
-       for (std::vector<const ld::Atom*>::const_iterator it=localAtoms.begin(); it != localAtoms.end(); ++it) {
-               const ld::Atom* atom = *it;
-               if ( this->addLocal(atom, this->_writer._stringPoolAtom) )
-                       this->_writer._atomToSymbolIndex[atom] = symbolIndex++;
-       }
-       this->_writer._localSymbolsCount = symbolIndex;
-       
+       // reserve space for local symbols
+       uint32_t localsCount = _state.stabs.size() + this->_writer._localAtoms.size();
 
        // make nlist entries for all global symbols
        std::vector<const ld::Atom*>& globalAtoms = this->_writer._exportedAtoms;
        _globals.reserve(globalAtoms.size());
-       this->_writer._globalSymbolsStartIndex = symbolIndex;
+       uint32_t symbolIndex = localsCount;
+       this->_writer._globalSymbolsStartIndex = localsCount;
        for (std::vector<const ld::Atom*>::const_iterator it=globalAtoms.begin(); it != globalAtoms.end(); ++it) {
                const ld::Atom* atom = *it;
                this->addGlobal(atom, this->_writer._stringPoolAtom);
@@ -660,6 +697,31 @@ void SymbolTableAtom<A>::encode()
                this->_writer._atomToSymbolIndex[*it] = symbolIndex++;
        }
        this->_writer._importSymbolsCount = symbolIndex - this->_writer._importSymbolsStartIndex;
+
+       // go back to start and make nlist entries for all local symbols
+       std::vector<const ld::Atom*>& localAtoms = this->_writer._localAtoms;
+       _locals.reserve(localsCount);
+       symbolIndex = 0;
+       this->_writer._localSymbolsStartIndex = 0;
+       _stabsIndexStart = 0;
+       _stabsStringsOffsetStart = this->_writer._stringPoolAtom->currentOffset();
+       for (const ld::relocatable::File::Stab& stab : _state.stabs) {
+               macho_nlist<P> entry;
+               entry.set_n_type(stab.type);
+               entry.set_n_sect(sectionIndexForStab(stab));
+               entry.set_n_desc(stab.desc);
+               entry.set_n_value(valueForStab(stab));
+               entry.set_n_strx(stringOffsetForStab(stab, this->_writer._stringPoolAtom));
+               _locals.push_back(entry);
+               ++symbolIndex;
+       }
+       _stabsIndexEnd = symbolIndex;
+       _stabsStringsOffsetEnd = this->_writer._stringPoolAtom->currentOffset();
+       for (const ld::Atom* atom : localAtoms) {
+               if ( this->addLocal(atom, this->_writer._stringPoolAtom) )
+                       this->_writer._atomToSymbolIndex[atom] = symbolIndex++;
+       }
+       this->_writer._localSymbolsCount = symbolIndex;
 }
 
 template <typename A>
@@ -766,13 +828,13 @@ uint64_t LocalRelocationsAtom<x86_64>::relocBaseAddress(ld::Internal& state)
                // for kext bundles the reloc base address starts at __TEXT segment
                return _options.baseAddress();
        }
-       // for all other kinds, the x86_64 reloc base address starts at __DATA segment
+       // for all other kinds, the x86_64 reloc base address starts at first writable segment (usually __DATA)
        for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
                ld::Internal::FinalSection* sect = *sit;
-               if ( strcmp(sect->segmentName(), "__DATA") == 0 )
+               if ( !sect->isSectionHidden() && _options.initialSegProtection(sect->segmentName()) & VM_PROT_WRITE )
                        return sect->address;
        }
-       throw "__DATA segment not found";
+       throw "writable (__DATA) segment not found";
 }
 
 template <typename A>
@@ -797,52 +859,6 @@ void LocalRelocationsAtom<A>::addPointerReloc(uint64_t addr, uint32_t symNum)
 template <typename A>
 void LocalRelocationsAtom<A>::addTextReloc(uint64_t addr, ld::Fixup::Kind kind, uint64_t targetAddr, uint32_t symNum)
 {
-       macho_relocation_info<P> reloc1;
-       macho_relocation_info<P> reloc2;
-       switch ( kind ) {
-               case ld::Fixup::kindStorePPCAbsLow14:
-               case ld::Fixup::kindStorePPCAbsLow16:
-                       // a reference to the absolute address of something in this same linkage unit can be 
-                       // encoded as a local text reloc in a dylib or bundle 
-                       if ( _options.outputSlidable() ) {
-                               reloc1.set_r_address(addr);
-                               reloc1.set_r_symbolnum(symNum);
-                               reloc1.set_r_pcrel(false);
-                               reloc1.set_r_length(2);
-                               reloc1.set_r_extern(false);
-                               reloc1.set_r_type(kind==ld::Fixup::kindStorePPCAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
-                               reloc2.set_r_address(targetAddr >> 16);
-                               reloc2.set_r_symbolnum(0);
-                               reloc2.set_r_pcrel(false);
-                               reloc2.set_r_length(2);
-                               reloc2.set_r_extern(false);
-                               reloc2.set_r_type(PPC_RELOC_PAIR);
-                               _relocs.push_back(reloc1);
-                               _relocs.push_back(reloc2);
-                       }
-                       break;
-               case ld::Fixup::kindStorePPCAbsHigh16AddLow:
-               case ld::Fixup::kindStorePPCAbsHigh16:
-                       if ( _options.outputSlidable() ) {
-                               reloc1.set_r_address(addr);
-                               reloc1.set_r_symbolnum(symNum);
-                               reloc1.set_r_pcrel(false);
-                               reloc1.set_r_length(2);
-                               reloc1.set_r_extern(false);
-                               reloc1.set_r_type(kind==ld::Fixup::kindStorePPCAbsHigh16AddLow ? PPC_RELOC_HA16 : PPC_RELOC_HI16);
-                               reloc2.set_r_address(targetAddr & 0xFFFF);
-                               reloc2.set_r_symbolnum(0);
-                               reloc2.set_r_pcrel(false);
-                               reloc2.set_r_length(2);
-                               reloc2.set_r_extern(false);
-                               reloc2.set_r_type(PPC_RELOC_PAIR);
-                               _relocs.push_back(reloc1);
-                               _relocs.push_back(reloc2);
-                       }
-                       break;
-               default:
-                       break;
-       }
 }
 
 
@@ -929,10 +945,10 @@ uint64_t ExternalRelocationsAtom<x86_64>::relocBaseAddress(ld::Internal& state)
        // for x86_64 the reloc base address starts at __DATA segment
        for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
                ld::Internal::FinalSection* sect = *sit;
-               if ( strcmp(sect->segmentName(), "__DATA") == 0 )
+               if ( !sect->isSectionHidden() && _options.initialSegProtection(sect->segmentName()) & VM_PROT_WRITE )
                        return sect->address;
        }
-       throw "__DATA segment not found";
+       throw "writable (__DATA) segment not found";
 }
 
 template <typename A>
@@ -964,15 +980,22 @@ uint64_t ExternalRelocationsAtom<A>::size() const
        return (_pointerLocations.size() + _callSiteLocations.size()) * sizeof(macho_relocation_info<P>);
 }
 
+#if SUPPORT_ARCH_arm64
+template <> uint32_t ExternalRelocationsAtom<arm64>::pointerReloc() { return ARM64_RELOC_UNSIGNED; }
+#endif
+#if SUPPORT_ARCH_arm_any
 template <> uint32_t ExternalRelocationsAtom<arm>::pointerReloc() { return ARM_RELOC_VANILLA; }
+#endif
 template <> uint32_t ExternalRelocationsAtom<x86>::pointerReloc() { return GENERIC_RELOC_VANILLA; }
-template <> uint32_t ExternalRelocationsAtom<ppc>::pointerReloc() { return PPC_RELOC_VANILLA; }
 template <> uint32_t ExternalRelocationsAtom<x86_64>::pointerReloc() { return X86_64_RELOC_UNSIGNED; }
-template <> uint32_t ExternalRelocationsAtom<ppc64>::pointerReloc() { return PPC_RELOC_VANILLA; }
 
 
 template <> uint32_t ExternalRelocationsAtom<x86_64>::callReloc() { return X86_64_RELOC_BRANCH; }
 template <> uint32_t ExternalRelocationsAtom<x86>::callReloc() { return GENERIC_RELOC_VANILLA; }
+#if SUPPORT_ARCH_arm64
+template <> uint32_t ExternalRelocationsAtom<arm64>::callReloc() { return ARM64_RELOC_BRANCH26; }
+#endif
+
 template <typename A> 
 uint32_t ExternalRelocationsAtom<A>::callReloc() 
 { 
@@ -1265,6 +1288,15 @@ void SectionRelocationsAtom<x86_64>::encodeSectionReloc(ld::Internal::FinalSecti
                                relocs.push_back(reloc1);
                        }
                        break;
+               case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolNum);
+                       reloc1.set_r_pcrel(true);
+                       reloc1.set_r_length(2);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(X86_64_RELOC_TLV);
+                       relocs.push_back(reloc1);
+                       break;
                default:
                        assert(0 && "need to handle -r reloc");
                
@@ -1286,7 +1318,7 @@ uint32_t SectionRelocationsAtom<A>::sectSymNum(bool external, const ld::Atom* ta
 }
 
 template <>
-void SectionRelocationsAtom<x86>::encodeSectionReloc(ld::Internal::FinalSection* sect, 
+void SectionRelocationsAtom<x86>::encodeSectionReloc(ld::Internal::FinalSection* sect,
                                                                                                        const Entry& entry, std::vector<macho_relocation_info<P> >& relocs)
 {
        macho_relocation_info<P> reloc1;
@@ -1302,8 +1334,7 @@ void SectionRelocationsAtom<x86>::encodeSectionReloc(ld::Internal::FinalSection*
                fromExternal = entry.fromTargetUsesExternalReloc;
                fromSymbolNum = sectSymNum(fromExternal, entry.fromTarget);
        }
-       
-       
+
        switch ( entry.kind ) {
                case ld::Fixup::kindStoreX86PCRel32:
                case ld::Fixup::kindStoreX86BranchPCRel32:
@@ -1384,8 +1415,12 @@ void SectionRelocationsAtom<x86>::encodeSectionReloc(ld::Internal::FinalSection*
                                else
                                        sreloc1->set_r_type(GENERIC_RELOC_SECTDIFF);
                                sreloc1->set_r_address(address);
-                               if ( entry.toTarget == entry.inAtom )
-                                       sreloc1->set_r_value(entry.toTarget->finalAddress()+entry.toAddend);
+                               if ( entry.toTarget == entry.inAtom ) {
+                                       if ( entry.toAddend > entry.toTarget->size() ) 
+                                               sreloc1->set_r_value(entry.toTarget->finalAddress()+entry.offsetInAtom);
+                                       else
+                                               sreloc1->set_r_value(entry.toTarget->finalAddress()+entry.toAddend);
+                               }
                                else
                                        sreloc1->set_r_value(entry.toTarget->finalAddress());
                                sreloc2->set_r_scattered(true);
@@ -1406,8 +1441,8 @@ void SectionRelocationsAtom<x86>::encodeSectionReloc(ld::Internal::FinalSection*
                        }
                        else {
                                // regular pointer
-                               if ( !external && (entry.toAddend != 0) ) {
-                                       // use scattered reloc is target offset is non-zero
+                               if ( !external && (entry.toAddend != 0) && (entry.toTarget->symbolTableInclusion() != ld::Atom::symbolTableNotIn) ) {
+                                       // use scattered reloc if target offset is non-zero into named atom (5658046)
                                        sreloc1->set_r_scattered(true);
                                        sreloc1->set_r_pcrel(false);
                                        sreloc1->set_r_length(2);
@@ -1426,6 +1461,17 @@ void SectionRelocationsAtom<x86>::encodeSectionReloc(ld::Internal::FinalSection*
                                relocs.push_back(reloc1);
                        }
                        break;
+               case ld::Fixup::kindStoreX86PCRel32TLVLoad:
+               case ld::Fixup::kindStoreX86Abs32TLVLoad:
+               case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolNum);
+                       reloc1.set_r_pcrel(entry.kind == ld::Fixup::kindStoreX86PCRel32TLVLoad);
+                       reloc1.set_r_length(2);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(GENERIC_RLEOC_TLV);
+                       relocs.push_back(reloc1);
+                       break;
                default:
                        assert(0 && "need to handle -r reloc");
                
@@ -1433,6 +1479,8 @@ void SectionRelocationsAtom<x86>::encodeSectionReloc(ld::Internal::FinalSection*
 }
 
 
+
+#if SUPPORT_ARCH_arm_any
 template <>
 void SectionRelocationsAtom<arm>::encodeSectionReloc(ld::Internal::FinalSection* sect, 
                                                                                                        const Entry& entry, std::vector<macho_relocation_info<P> >& relocs)
@@ -1513,10 +1561,15 @@ void SectionRelocationsAtom<arm>::encodeSectionReloc(ld::Internal::FinalSection*
                                else
                                        sreloc1->set_r_type(ARM_RELOC_SECTDIFF);
                                sreloc1->set_r_address(address);
-                               if ( entry.toTarget == entry.inAtom )
-                                       sreloc1->set_r_value(entry.toTarget->finalAddress()+entry.toAddend);
-                               else
+                               if ( entry.toTarget == entry.inAtom ) {
+                                       if ( entry.toAddend > entry.toTarget->size() ) 
+                                               sreloc1->set_r_value(entry.toTarget->finalAddress()+entry.offsetInAtom);
+                                       else
+                                               sreloc1->set_r_value(entry.toTarget->finalAddress()+entry.toAddend);
+                               }
+                               else {
                                        sreloc1->set_r_value(entry.toTarget->finalAddress());
+                               }
                                sreloc2->set_r_scattered(true);
                                sreloc2->set_r_pcrel(false);
                                sreloc2->set_r_length(2);
@@ -1565,9 +1618,17 @@ void SectionRelocationsAtom<arm>::encodeSectionReloc(ld::Internal::FinalSection*
                        {
                                int len = 0;
                                uint32_t otherHalf = 0;
-                               uint32_t value = entry.toTarget->finalAddress()+entry.toAddend;
-                               if ( entry.fromTarget != NULL ) 
-                                       value -= (entry.fromTarget->finalAddress()+entry.fromAddend);
+                               uint32_t value;
+                               if ( entry.fromTarget != NULL )  {
+                                 // this is a sect-diff
+                                 value = (entry.toTarget->finalAddress()+entry.toAddend) - (entry.fromTarget->finalAddress()+entry.fromAddend);
+                               }
+                               else {
+                                       // this is an absolute address
+                                       value = entry.toAddend;
+                                       if ( !external )
+                                               value += entry.toTarget->finalAddress();
+                               }
                                switch ( entry.kind ) {
                                        case ld::Fixup::kindStoreARMLow16:
                                                len = 0;
@@ -1632,7 +1693,7 @@ void SectionRelocationsAtom<arm>::encodeSectionReloc(ld::Internal::FinalSection*
                                                reloc1.set_r_symbolnum(symbolNum);
                                                reloc1.set_r_pcrel(false);
                                                reloc1.set_r_length(len);
-                                               reloc1.set_r_extern(false);
+                                               reloc1.set_r_extern(external);
                                                reloc1.set_r_type(ARM_RELOC_HALF);
                                                reloc2.set_r_address(otherHalf);  // other half
                                                reloc2.set_r_symbolnum(0);
@@ -1652,16 +1713,15 @@ void SectionRelocationsAtom<arm>::encodeSectionReloc(ld::Internal::FinalSection*
                
        }
 }
+#endif
 
-
+#if SUPPORT_ARCH_arm64
 template <>
-void SectionRelocationsAtom<ppc>::encodeSectionReloc(ld::Internal::FinalSection* sect, 
+void SectionRelocationsAtom<arm64>::encodeSectionReloc(ld::Internal::FinalSection* sect, 
                                                                                                        const Entry& entry, std::vector<macho_relocation_info<P> >& relocs)
 {
        macho_relocation_info<P> reloc1;
        macho_relocation_info<P> reloc2;
-       macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
-       macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
        uint64_t address = entry.inAtom->finalAddress()+entry.offsetInAtom - sect->address;
        bool external = entry.toTargetUsesExternalReloc;
        uint32_t symbolNum = sectSymNum(external, entry.toTarget);
@@ -1669,567 +1729,213 @@ void SectionRelocationsAtom<ppc>::encodeSectionReloc(ld::Internal::FinalSection*
        uint32_t fromSymbolNum = 0;
        if ( entry.fromTarget != NULL ) {
                fromExternal = entry.fromTargetUsesExternalReloc;
-               fromSymbolNum= sectSymNum(fromExternal, entry.fromTarget);
+               fromSymbolNum = sectSymNum(fromExternal, entry.fromTarget);
        }
-       uint32_t toAddr;
-       uint32_t fromAddr;
        
-       switch ( entry.kind ) {
        
-               case ld::Fixup::kindStorePPCBranch24:
-               case ld::Fixup::kindStoreTargetAddressPPCBranch24:
-               case ld::Fixup::kindStorePPCDtraceCallSiteNop:
-               case ld::Fixup::kindStorePPCDtraceIsEnableSiteClear:
-                       if ( !external && (entry.toAddend != 0) ) {
-                               // use scattered reloc if target offset is non-zero
-                               sreloc1->set_r_scattered(true);
-                               sreloc1->set_r_pcrel(true);
-                               sreloc1->set_r_length(2);
-                               sreloc1->set_r_type(PPC_RELOC_BR24);
-                               sreloc1->set_r_address(address);
-                               sreloc1->set_r_value(entry.toTarget->finalAddress());
-                       }
-                       else {
-                               reloc1.set_r_address(address);
-                               reloc1.set_r_symbolnum(symbolNum);
-                               reloc1.set_r_pcrel(true);
-                               reloc1.set_r_length(2);
-                               reloc1.set_r_extern(external);
-                               reloc1.set_r_type(PPC_RELOC_BR24);
-                       }
-                       relocs.push_back(reloc1);
-                       break;
-
-               case ld::Fixup::kindStorePPCBranch14:
-                       if ( !external && (entry.toAddend != 0) ) {
-                               // use scattered reloc if target offset is non-zero
-                               sreloc1->set_r_scattered(true);
-                               sreloc1->set_r_pcrel(true);
-                               sreloc1->set_r_length(2);
-                               sreloc1->set_r_type(PPC_RELOC_BR14);
-                               sreloc1->set_r_address(address);
-                               sreloc1->set_r_value(entry.toTarget->finalAddress());
-                       }
-                       else {
-                               reloc1.set_r_address(address);
-                               reloc1.set_r_symbolnum(symbolNum);
-                               reloc1.set_r_pcrel(true);
-                               reloc1.set_r_length(2);
-                               reloc1.set_r_extern(external);
-                               reloc1.set_r_type(PPC_RELOC_BR14);
-                       }
-                       relocs.push_back(reloc1);
-                       break;
-
-               case ld::Fixup::kindStoreBigEndian32:
-               case ld::Fixup::kindStoreTargetAddressBigEndian32:
-                       if ( entry.fromTarget != NULL ) {
-                               // this is a pointer-diff
-                               sreloc1->set_r_scattered(true);
-                               sreloc1->set_r_pcrel(false);
-                               sreloc1->set_r_length(2);
-                               if ( entry.toTarget->scope() == ld::Atom::scopeTranslationUnit )
-                                       sreloc1->set_r_type(PPC_RELOC_LOCAL_SECTDIFF);
-                               else
-                                       sreloc1->set_r_type(PPC_RELOC_SECTDIFF);
-                               sreloc1->set_r_address(address);
-                               if ( entry.toTarget == entry.inAtom )
-                                       sreloc1->set_r_value(entry.toTarget->finalAddress()+entry.toAddend);
-                               else
-                                       sreloc1->set_r_value(entry.toTarget->finalAddress());
-                               sreloc2->set_r_scattered(true);
-                               sreloc2->set_r_pcrel(false);
-                               sreloc2->set_r_length(2);
-                               sreloc2->set_r_type(PPC_RELOC_PAIR);
-                               sreloc2->set_r_address(0);
-                               if ( entry.fromTarget == entry.inAtom ) {
-                                       if ( entry.fromAddend > entry.fromTarget->size() )
-                                               sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.offsetInAtom);
-                                       else
-                                               sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.fromAddend);
-                               }
-                               else
-                                       sreloc2->set_r_value(entry.fromTarget->finalAddress());
-                               relocs.push_back(reloc1);
+       switch ( entry.kind ) {
+               case ld::Fixup::kindStoreARM64Branch26:
+                       if ( entry.toAddend != 0 ) {
+                               assert(entry.toAddend < 0x400000);
+                               reloc2.set_r_address(address);
+                               reloc2.set_r_symbolnum(entry.toAddend);
+                               reloc2.set_r_pcrel(false);
+                               reloc2.set_r_length(2);
+                               reloc2.set_r_extern(false);
+                               reloc2.set_r_type(ARM64_RELOC_ADDEND);
                                relocs.push_back(reloc2);
                        }
-                       else {
-                               // regular pointer
-                               if ( !external && (entry.toAddend != 0) ) {
-                                       // use scattered reloc is target offset is non-zero
-                                       sreloc1->set_r_scattered(true);
-                                       sreloc1->set_r_pcrel(false);
-                                       sreloc1->set_r_length(2);
-                                       sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
-                                       sreloc1->set_r_address(address);
-                                       sreloc1->set_r_value(entry.toTarget->finalAddress());
-                               }
-                               else {
-                                       reloc1.set_r_address(address);
-                                       reloc1.set_r_symbolnum(symbolNum);
-                                       reloc1.set_r_pcrel(false);
-                                       reloc1.set_r_length(2);
-                                       reloc1.set_r_extern(external);
-                                       reloc1.set_r_type(GENERIC_RELOC_VANILLA);
-                               }
-                               relocs.push_back(reloc1);
-                       }
-                       break;
-                       
-               case ld::Fixup::kindStorePPCAbsLow14:
-               case ld::Fixup::kindStorePPCAbsLow16:
-                       if ( !external && (entry.toAddend != 0) ) {
-                               // use scattered reloc if target offset is non-zero
-                               sreloc1->set_r_scattered(true);
-                               sreloc1->set_r_pcrel(false);
-                               sreloc1->set_r_length(2);
-                               sreloc1->set_r_type(entry.kind==ld::Fixup::kindStorePPCAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
-                               sreloc1->set_r_address(address);
-                               sreloc1->set_r_value(entry.toTarget->finalAddress());
-                       }
-                       else {
-                               reloc1.set_r_address(address);
-                               reloc1.set_r_symbolnum(symbolNum);
-                               reloc1.set_r_pcrel(false);
-                               reloc1.set_r_length(2);
-                               reloc1.set_r_extern(external);
-                               reloc1.set_r_type(entry.kind==ld::Fixup::kindStorePPCAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
-                       }
-                       if ( external )
-                               reloc2.set_r_address(entry.toAddend >> 16);
-                       else
-                               reloc2.set_r_address((entry.toTarget->finalAddress()+entry.toAddend) >> 16);
-                       reloc2.set_r_symbolnum(0);
-                       reloc2.set_r_pcrel(false);
-                       reloc2.set_r_length(2);
-                       reloc2.set_r_extern(false);
-                       reloc2.set_r_type(PPC_RELOC_PAIR);
+                       // fall into next case
+               case ld::Fixup::kindStoreTargetAddressARM64Branch26:
+               case ld::Fixup::kindStoreARM64DtraceCallSiteNop:
+               case ld::Fixup::kindStoreARM64DtraceIsEnableSiteClear:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolNum);
+                       reloc1.set_r_pcrel(true);
+                       reloc1.set_r_length(2);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(ARM64_RELOC_BRANCH26);
                        relocs.push_back(reloc1);
-                       relocs.push_back(reloc2);
                        break;
                        
-               case ld::Fixup::kindStorePPCAbsHigh16:
-                       if ( !external && (entry.toAddend != 0) ) {
-                               // use scattered reloc if target offset is non-zero
-                               sreloc1->set_r_scattered(true);
-                               sreloc1->set_r_pcrel(false);
-                               sreloc1->set_r_length(2);
-                               sreloc1->set_r_type(PPC_RELOC_HI16);
-                               sreloc1->set_r_address(address);
-                               sreloc1->set_r_value(entry.toTarget->finalAddress());
-                       }
-                       else {
-                               reloc1.set_r_address(address);
-                               reloc1.set_r_symbolnum(symbolNum);
-                               reloc1.set_r_pcrel(false);
-                               reloc1.set_r_length(2);
-                               reloc1.set_r_extern(external);
-                               reloc1.set_r_type(PPC_RELOC_HI16);
+               case ld::Fixup::kindStoreARM64Page21:
+                       if ( entry.toAddend != 0 ) {
+                               assert(entry.toAddend < 0x400000);
+                               reloc2.set_r_address(address);
+                               reloc2.set_r_symbolnum(entry.toAddend);
+                               reloc2.set_r_pcrel(false);
+                               reloc2.set_r_length(2);
+                               reloc2.set_r_extern(false);
+                               reloc2.set_r_type(ARM64_RELOC_ADDEND);
+                               relocs.push_back(reloc2);
                        }
-                       if ( external )
-                               reloc2.set_r_address(entry.toAddend & 0x0000FFFF);
-                       else
-                               reloc2.set_r_address((entry.toTarget->finalAddress()+entry.toAddend) & 0x0000FFFF);
-                       reloc2.set_r_symbolnum(0);
-                       reloc2.set_r_pcrel(false);
-                       reloc2.set_r_length(2);
-                       reloc2.set_r_extern(false);
-                       reloc2.set_r_type(PPC_RELOC_PAIR);
+                       // fall into next case
+               case ld::Fixup::kindStoreTargetAddressARM64Page21:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolNum);
+                       reloc1.set_r_pcrel(true);
+                       reloc1.set_r_length(2);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(ARM64_RELOC_PAGE21);
                        relocs.push_back(reloc1);
-                       relocs.push_back(reloc2);
                        break;
-                       
-               case ld::Fixup::kindStorePPCAbsHigh16AddLow:
-                       if ( !external && (entry.toAddend != 0) ) {
-                               // use scattered reloc if target offset is non-zero
-                               sreloc1->set_r_scattered(true);
-                               sreloc1->set_r_pcrel(false);
-                               sreloc1->set_r_length(2);
-                               sreloc1->set_r_type(PPC_RELOC_HA16);
-                               sreloc1->set_r_address(address);
-                               sreloc1->set_r_value(entry.toTarget->finalAddress());
-                       }
-                       else {
-                               reloc1.set_r_address(address);
-                               reloc1.set_r_symbolnum(symbolNum);
-                               reloc1.set_r_pcrel(false);
-                               reloc1.set_r_length(2);
-                               reloc1.set_r_extern(external);
-                               reloc1.set_r_type(PPC_RELOC_HA16);
+
+               case ld::Fixup::kindStoreARM64PageOff12:
+                       if ( entry.toAddend != 0 ) {
+                               assert(entry.toAddend < 0x400000);
+                               reloc2.set_r_address(address);
+                               reloc2.set_r_symbolnum(entry.toAddend);
+                               reloc2.set_r_pcrel(false);
+                               reloc2.set_r_length(2);
+                               reloc2.set_r_extern(false);
+                               reloc2.set_r_type(ARM64_RELOC_ADDEND);
+                               relocs.push_back(reloc2);
                        }
-                       if ( external )
-                               reloc2.set_r_address(entry.toAddend & 0x0000FFFF);
-                       else
-                               reloc2.set_r_address((entry.toTarget->finalAddress()+entry.toAddend) & 0x0000FFFF);
-                       reloc2.set_r_symbolnum(0);
-                       reloc2.set_r_pcrel(false);
-                       reloc2.set_r_length(2);
-                       reloc2.set_r_extern(false);
-                       reloc2.set_r_type(PPC_RELOC_PAIR);
+                       // fall into next case
+               case ld::Fixup::kindStoreTargetAddressARM64PageOff12:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolNum);
+                       reloc1.set_r_pcrel(false);
+                       reloc1.set_r_length(2);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(ARM64_RELOC_PAGEOFF12);
                        relocs.push_back(reloc1);
-                       relocs.push_back(reloc2);
                        break;
-                       
-               case ld::Fixup::kindStorePPCPicLow14:
-               case ld::Fixup::kindStorePPCPicLow16:
-                       fromAddr = entry.fromTarget->finalAddress() + entry.fromAddend;
-                       toAddr = entry.toTarget->finalAddress() + entry.toAddend;
-                       sreloc1->set_r_scattered(true);
-                       sreloc1->set_r_pcrel(false);
-                       sreloc1->set_r_length(2);
-                       sreloc1->set_r_type(entry.kind == ld::Fixup::kindStorePPCPicLow16 ? PPC_RELOC_LO16_SECTDIFF : PPC_RELOC_LO14_SECTDIFF);
-                       sreloc1->set_r_address(address);
-                       sreloc1->set_r_value(entry.toTarget->finalAddress());
-                       sreloc2->set_r_scattered(true);
-                       sreloc2->set_r_pcrel(false);
-                       sreloc2->set_r_length(2);
-                       sreloc2->set_r_type(PPC_RELOC_PAIR);
-                       sreloc2->set_r_address(((toAddr-fromAddr) >> 16) & 0xFFFF);
-                       sreloc2->set_r_value(fromAddr);
+
+               case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
+               case ld::Fixup::kindStoreARM64GOTLoadPage21:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolNum);
+                       reloc1.set_r_pcrel(true);
+                       reloc1.set_r_length(2);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(ARM64_RELOC_GOT_LOAD_PAGE21);
                        relocs.push_back(reloc1);
-                       relocs.push_back(reloc2);
                        break;
-                       
-               case ld::Fixup::kindStorePPCPicHigh16AddLow:
-                       fromAddr = entry.fromTarget->finalAddress() + entry.fromAddend;
-                       toAddr = entry.toTarget->finalAddress() + entry.toAddend;
-                       sreloc1->set_r_scattered(true);
-                       sreloc1->set_r_pcrel(false);
-                       sreloc1->set_r_length(2);
-                       sreloc1->set_r_type(PPC_RELOC_HA16_SECTDIFF);
-                       sreloc1->set_r_address(address);
-                       sreloc1->set_r_value(entry.toTarget->finalAddress());
-                       sreloc2->set_r_scattered(true);
-                       sreloc2->set_r_pcrel(false);
-                       sreloc2->set_r_length(2);
-                       sreloc2->set_r_type(PPC_RELOC_PAIR);
-                       sreloc2->set_r_address((toAddr-fromAddr) & 0xFFFF);
-                       sreloc2->set_r_value(fromAddr);
+
+               case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12:
+               case ld::Fixup::kindStoreARM64GOTLoadPageOff12:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolNum);
+                       reloc1.set_r_pcrel(false);
+                       reloc1.set_r_length(2);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(ARM64_RELOC_GOT_LOAD_PAGEOFF12);
                        relocs.push_back(reloc1);
-                       relocs.push_back(reloc2);
                        break;
-                       
-               default:
-                       assert(0 && "need to handle -r reloc");
-               
-       }
-}
 
-template <>
-void SectionRelocationsAtom<ppc64>::encodeSectionReloc(ld::Internal::FinalSection* sect, 
-                                                                                                       const Entry& entry, std::vector<macho_relocation_info<P> >& relocs)
-{
-       macho_relocation_info<P> reloc1;
-       macho_relocation_info<P> reloc2;
-       macho_scattered_relocation_info<P>* sreloc1 = (macho_scattered_relocation_info<P>*)&reloc1;
-       macho_scattered_relocation_info<P>* sreloc2 = (macho_scattered_relocation_info<P>*)&reloc2;
-       uint64_t address = entry.inAtom->finalAddress()+entry.offsetInAtom - sect->address;
-       bool external = entry.toTargetUsesExternalReloc;
-       uint32_t symbolNum = sectSymNum(external, entry.toTarget);
-       bool fromExternal = false;
-       uint32_t fromSymbolNum = 0;
-       if ( entry.fromTarget != NULL ) {
-               fromExternal = entry.fromTargetUsesExternalReloc;
-               fromSymbolNum= sectSymNum(fromExternal, entry.fromTarget);
-       }
-       uint32_t toAddr;
-       uint32_t fromAddr;
-       
-       switch ( entry.kind ) {
-       
-               case ld::Fixup::kindStorePPCBranch24:
-               case ld::Fixup::kindStoreTargetAddressPPCBranch24:
-               case ld::Fixup::kindStorePPCDtraceCallSiteNop:
-               case ld::Fixup::kindStorePPCDtraceIsEnableSiteClear:
-                       if ( !external && (entry.toAddend != 0) ) {
-                               // use scattered reloc if target offset is non-zero
-                               sreloc1->set_r_scattered(true);
-                               sreloc1->set_r_pcrel(true);
-                               sreloc1->set_r_length(2);
-                               sreloc1->set_r_type(PPC_RELOC_BR24);
-                               sreloc1->set_r_address(address);
-                               sreloc1->set_r_value(entry.toTarget->finalAddress());
-                       }
-                       else {
-                               reloc1.set_r_address(address);
-                               reloc1.set_r_symbolnum(symbolNum);
-                               reloc1.set_r_pcrel(true);
-                               reloc1.set_r_length(2);
-                               reloc1.set_r_extern(external);
-                               reloc1.set_r_type(PPC_RELOC_BR24);
-                       }
+               case ld::Fixup::kindStoreARM64TLVPLoadPageOff12:
+               case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPageOff12:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolNum);
+                       reloc1.set_r_pcrel(false);
+                       reloc1.set_r_length(2);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(ARM64_RELOC_TLVP_LOAD_PAGEOFF12);
                        relocs.push_back(reloc1);
                        break;
 
-               case ld::Fixup::kindStorePPCBranch14:
-                       if ( !external && (entry.toAddend != 0) ) {
-                               // use scattered reloc if target offset is non-zero
-                               sreloc1->set_r_scattered(true);
-                               sreloc1->set_r_pcrel(true);
-                               sreloc1->set_r_length(2);
-                               sreloc1->set_r_type(PPC_RELOC_BR14);
-                               sreloc1->set_r_address(address);
-                               sreloc1->set_r_value(entry.toTarget->finalAddress());
-                       }
-                       else {
-                               reloc1.set_r_address(address);
-                               reloc1.set_r_symbolnum(symbolNum);
-                               reloc1.set_r_pcrel(true);
-                               reloc1.set_r_length(2);
-                               reloc1.set_r_extern(external);
-                               reloc1.set_r_type(PPC_RELOC_BR14);
-                       }
+               case ld::Fixup::kindStoreARM64TLVPLoadPage21:
+               case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPage21:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolNum);
+                       reloc1.set_r_pcrel(true);
+                       reloc1.set_r_length(2);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(ARM64_RELOC_TLVP_LOAD_PAGE21);
                        relocs.push_back(reloc1);
                        break;
 
-               case ld::Fixup::kindStoreBigEndian32:
-               case ld::Fixup::kindStoreTargetAddressBigEndian32:
+               case ld::Fixup::kindStoreLittleEndian64:
+               case ld::Fixup::kindStoreTargetAddressLittleEndian64:
                        if ( entry.fromTarget != NULL ) {
                                // this is a pointer-diff
-                               sreloc1->set_r_scattered(true);
-                               sreloc1->set_r_pcrel(false);
-                               sreloc1->set_r_length(2);
-                               if ( entry.toTarget->scope() == ld::Atom::scopeTranslationUnit )
-                                       sreloc1->set_r_type(PPC_RELOC_LOCAL_SECTDIFF);
-                               else
-                                       sreloc1->set_r_type(PPC_RELOC_SECTDIFF);
-                               sreloc1->set_r_address(address);
-                               if ( entry.toTarget == entry.inAtom )
-                                       sreloc1->set_r_value(entry.toTarget->finalAddress()+entry.toAddend);
-                               else
-                                       sreloc1->set_r_value(entry.toTarget->finalAddress());
-                               sreloc2->set_r_scattered(true);
-                               sreloc2->set_r_pcrel(false);
-                               sreloc2->set_r_length(2);
-                               sreloc2->set_r_type(PPC_RELOC_PAIR);
-                               sreloc2->set_r_address(0);
-                               if ( entry.fromTarget == entry.inAtom ) {
-                                       if ( entry.fromAddend > entry.fromTarget->size() )
-                                               sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.offsetInAtom);
-                                       else
-                                               sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.fromAddend);
-                               }
-                               else
-                                       sreloc2->set_r_value(entry.fromTarget->finalAddress());
-                               relocs.push_back(reloc1);
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(false);
+                               reloc1.set_r_length(3);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(ARM64_RELOC_UNSIGNED);
+                               reloc2.set_r_address(address);
+                               reloc2.set_r_symbolnum(fromSymbolNum);
+                               reloc2.set_r_pcrel(false);
+                               reloc2.set_r_length(3);
+                               reloc2.set_r_extern(fromExternal);
+                               reloc2.set_r_type(ARM64_RELOC_SUBTRACTOR);
                                relocs.push_back(reloc2);
-                       }
-                       else {
-                               // regular pointer
-                               if ( !external && (entry.toAddend != 0) ) {
-                                       // use scattered reloc is target offset is non-zero
-                                       sreloc1->set_r_scattered(true);
-                                       sreloc1->set_r_pcrel(false);
-                                       sreloc1->set_r_length(2);
-                                       sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
-                                       sreloc1->set_r_address(address);
-                                       sreloc1->set_r_value(entry.toTarget->finalAddress());
-                               }
-                               else {
-                                       reloc1.set_r_address(address);
-                                       reloc1.set_r_symbolnum(symbolNum);
-                                       reloc1.set_r_pcrel(false);
-                                       reloc1.set_r_length(2);
-                                       reloc1.set_r_extern(external);
-                                       reloc1.set_r_type(GENERIC_RELOC_VANILLA);
-                               }
-                               relocs.push_back(reloc1);
-                       }
-                       break;
-                       
-               case ld::Fixup::kindStoreBigEndian64:
-               case ld::Fixup::kindStoreTargetAddressBigEndian64:
-                       if ( entry.fromTarget != NULL ) {
-                               // this is a pointer-diff
-                               sreloc1->set_r_scattered(true);
-                               sreloc1->set_r_pcrel(false);
-                               sreloc1->set_r_length(3);
-                               if ( entry.toTarget->scope() == ld::Atom::scopeTranslationUnit )
-                                       sreloc1->set_r_type(PPC_RELOC_LOCAL_SECTDIFF);
-                               else
-                                       sreloc1->set_r_type(PPC_RELOC_SECTDIFF);
-                               sreloc1->set_r_address(address);
-                               if ( entry.toTarget == entry.inAtom )
-                                       sreloc1->set_r_value(entry.toTarget->finalAddress()+entry.toAddend);
-                               else
-                                       sreloc1->set_r_value(entry.toTarget->finalAddress());
-                               sreloc2->set_r_scattered(true);
-                               sreloc2->set_r_pcrel(false);
-                               sreloc2->set_r_length(3);
-                               sreloc2->set_r_type(PPC_RELOC_PAIR);
-                               sreloc2->set_r_address(0);
-                               if ( entry.fromTarget == entry.inAtom ) {
-                                       if ( entry.fromAddend > entry.fromTarget->size() )
-                                               sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.offsetInAtom);
-                                       else
-                                               sreloc2->set_r_value(entry.fromTarget->finalAddress()+entry.fromAddend);
-                               }
-                               else
-                                       sreloc2->set_r_value(entry.fromTarget->finalAddress());
                                relocs.push_back(reloc1);
-                               relocs.push_back(reloc2);
                        }
                        else {
                                // regular pointer
-                               if ( !external && (entry.toAddend != 0) ) {
-                                       // use scattered reloc is target offset is non-zero
-                                       sreloc1->set_r_scattered(true);
-                                       sreloc1->set_r_pcrel(false);
-                                       sreloc1->set_r_length(3);
-                                       sreloc1->set_r_type(GENERIC_RELOC_VANILLA);
-                                       sreloc1->set_r_address(address);
-                                       sreloc1->set_r_value(entry.toTarget->finalAddress());
-                               }
-                               else {
-                                       reloc1.set_r_address(address);
-                                       reloc1.set_r_symbolnum(symbolNum);
-                                       reloc1.set_r_pcrel(false);
-                                       reloc1.set_r_length(3);
-                                       reloc1.set_r_extern(external);
-                                       reloc1.set_r_type(GENERIC_RELOC_VANILLA);
-                               }
-                               relocs.push_back(reloc1);
-                       }
-                       break;
-
-               case ld::Fixup::kindStorePPCAbsLow14:
-               case ld::Fixup::kindStorePPCAbsLow16:
-                       if ( !external && (entry.toAddend != 0) ) {
-                               // use scattered reloc if target offset is non-zero
-                               sreloc1->set_r_scattered(true);
-                               sreloc1->set_r_pcrel(false);
-                               sreloc1->set_r_length(2);
-                               sreloc1->set_r_type(entry.kind==ld::Fixup::kindStorePPCAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
-                               sreloc1->set_r_address(address);
-                               sreloc1->set_r_value(entry.toTarget->finalAddress());
-                       }
-                       else {
                                reloc1.set_r_address(address);
                                reloc1.set_r_symbolnum(symbolNum);
                                reloc1.set_r_pcrel(false);
-                               reloc1.set_r_length(2);
+                               reloc1.set_r_length(3);
                                reloc1.set_r_extern(external);
-                               reloc1.set_r_type(entry.kind==ld::Fixup::kindStorePPCAbsLow16 ? PPC_RELOC_LO16 : PPC_RELOC_LO14);
+                               reloc1.set_r_type(ARM64_RELOC_UNSIGNED);
+                               relocs.push_back(reloc1);
                        }
-                       if ( external )
-                               reloc2.set_r_address(entry.toAddend >> 16);
-                       else
-                               reloc2.set_r_address((entry.toTarget->finalAddress()+entry.toAddend) >> 16);
-                       reloc2.set_r_symbolnum(0);
-                       reloc2.set_r_pcrel(false);
-                       reloc2.set_r_length(2);
-                       reloc2.set_r_extern(false);
-                       reloc2.set_r_type(PPC_RELOC_PAIR);
-                       relocs.push_back(reloc1);
-                       relocs.push_back(reloc2);
                        break;
-                       
-               case ld::Fixup::kindStorePPCAbsHigh16:
-                       if ( !external && (entry.toAddend != 0) ) {
-                               // use scattered reloc if target offset is non-zero
-                               sreloc1->set_r_scattered(true);
-                               sreloc1->set_r_pcrel(false);
-                               sreloc1->set_r_length(2);
-                               sreloc1->set_r_type(PPC_RELOC_HI16);
-                               sreloc1->set_r_address(address);
-                               sreloc1->set_r_value(entry.toTarget->finalAddress());
-                       }
-                       else {
+
+               case ld::Fixup::kindStoreLittleEndian32:
+               case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+                       if ( entry.fromTarget != NULL ) {
+                               // this is a pointer-diff
                                reloc1.set_r_address(address);
                                reloc1.set_r_symbolnum(symbolNum);
                                reloc1.set_r_pcrel(false);
                                reloc1.set_r_length(2);
                                reloc1.set_r_extern(external);
-                               reloc1.set_r_type(PPC_RELOC_HI16);
-                       }
-                       if ( external )
-                               reloc2.set_r_address(entry.toAddend & 0x0000FFFF);
-                       else
-                               reloc2.set_r_address((entry.toTarget->finalAddress()+entry.toAddend) & 0x0000FFFF);
-                       reloc2.set_r_symbolnum(0);
-                       reloc2.set_r_pcrel(false);
-                       reloc2.set_r_length(2);
-                       reloc2.set_r_extern(false);
-                       reloc2.set_r_type(PPC_RELOC_PAIR);
-                       relocs.push_back(reloc1);
-                       relocs.push_back(reloc2);
-                       break;
-                       
-               case ld::Fixup::kindStorePPCAbsHigh16AddLow:
-                       if ( !external && (entry.toAddend != 0) ) {
-                               // use scattered reloc if target offset is non-zero
-                               sreloc1->set_r_scattered(true);
-                               sreloc1->set_r_pcrel(false);
-                               sreloc1->set_r_length(2);
-                               sreloc1->set_r_type(PPC_RELOC_HA16);
-                               sreloc1->set_r_address(address);
-                               sreloc1->set_r_value(entry.toTarget->finalAddress());
+                               reloc1.set_r_type(ARM64_RELOC_UNSIGNED);
+                               reloc2.set_r_address(address);
+                               reloc2.set_r_symbolnum(fromSymbolNum);
+                               reloc2.set_r_pcrel(false);
+                               reloc2.set_r_length(2);
+                               reloc2.set_r_extern(fromExternal);
+                               reloc2.set_r_type(ARM64_RELOC_SUBTRACTOR);
+                               relocs.push_back(reloc2);
+                               relocs.push_back(reloc1);
                        }
                        else {
+                               // regular pointer
                                reloc1.set_r_address(address);
                                reloc1.set_r_symbolnum(symbolNum);
                                reloc1.set_r_pcrel(false);
                                reloc1.set_r_length(2);
                                reloc1.set_r_extern(external);
-                               reloc1.set_r_type(PPC_RELOC_HA16);
+                               reloc1.set_r_type(ARM64_RELOC_UNSIGNED);
+                               relocs.push_back(reloc1);
                        }
-                       if ( external )
-                               reloc2.set_r_address(entry.toAddend & 0x0000FFFF);
-                       else
-                               reloc2.set_r_address((entry.toTarget->finalAddress()+entry.toAddend) & 0x0000FFFF);
-                       reloc2.set_r_symbolnum(0);
-                       reloc2.set_r_pcrel(false);
-                       reloc2.set_r_length(2);
-                       reloc2.set_r_extern(false);
-                       reloc2.set_r_type(PPC_RELOC_PAIR);
-                       relocs.push_back(reloc1);
-                       relocs.push_back(reloc2);
-                       break;
-                       
-               case ld::Fixup::kindStorePPCPicLow14:
-               case ld::Fixup::kindStorePPCPicLow16:
-                       fromAddr = entry.fromTarget->finalAddress() + entry.fromAddend;
-                       toAddr = entry.toTarget->finalAddress() + entry.toAddend;
-                       sreloc1->set_r_scattered(true);
-                       sreloc1->set_r_pcrel(false);
-                       sreloc1->set_r_length(2);
-                       sreloc1->set_r_type(entry.kind == ld::Fixup::kindStorePPCPicLow16 ? PPC_RELOC_LO16_SECTDIFF : PPC_RELOC_LO14_SECTDIFF);
-                       sreloc1->set_r_address(address);
-                       sreloc1->set_r_value(entry.toTarget->finalAddress());
-                       sreloc2->set_r_scattered(true);
-                       sreloc2->set_r_pcrel(false);
-                       sreloc2->set_r_length(2);
-                       sreloc2->set_r_type(PPC_RELOC_PAIR);
-                       sreloc2->set_r_address(((toAddr-fromAddr) >> 16) & 0xFFFF);
-                       sreloc2->set_r_value(fromAddr);
-                       relocs.push_back(reloc1);
-                       relocs.push_back(reloc2);
                        break;
-                       
-               case ld::Fixup::kindStorePPCPicHigh16AddLow:
-                       fromAddr = entry.fromTarget->finalAddress() + entry.fromAddend;
-                       toAddr = entry.toTarget->finalAddress() + entry.toAddend;
-                       sreloc1->set_r_scattered(true);
-                       sreloc1->set_r_pcrel(false);
-                       sreloc1->set_r_length(2);
-                       sreloc1->set_r_type(PPC_RELOC_HA16_SECTDIFF);
-                       sreloc1->set_r_address(address);
-                       sreloc1->set_r_value(entry.toTarget->finalAddress());
-                       sreloc2->set_r_scattered(true);
-                       sreloc2->set_r_pcrel(false);
-                       sreloc2->set_r_length(2);
-                       sreloc2->set_r_type(PPC_RELOC_PAIR);
-                       sreloc2->set_r_address((toAddr-fromAddr) & 0xFFFF);
-                       sreloc2->set_r_value(fromAddr);
-                       relocs.push_back(reloc1);
-                       relocs.push_back(reloc2);
-                       break;
-                       
+
+               case ld::Fixup::kindStoreARM64PointerToGOT:
+            reloc1.set_r_address(address);
+            reloc1.set_r_symbolnum(symbolNum);
+            reloc1.set_r_pcrel(false);
+            reloc1.set_r_length(3);
+            reloc1.set_r_extern(external);
+            reloc1.set_r_type(ARM64_RELOC_POINTER_TO_GOT);
+            relocs.push_back(reloc1);
+            break;
+
+               case ld::Fixup::kindStoreARM64PCRelToGOT:
+            reloc1.set_r_address(address);
+            reloc1.set_r_symbolnum(symbolNum);
+            reloc1.set_r_pcrel(true);
+            reloc1.set_r_length(2);
+            reloc1.set_r_extern(external);
+            reloc1.set_r_type(ARM64_RELOC_POINTER_TO_GOT);
+            relocs.push_back(reloc1);
+            break;
+
                default:
-                       assert(0 && "need to handle -r reloc");
+                       assert(0 && "need to handle arm64 -r reloc");
                
        }
+
 }
+#endif // SUPPORT_ARCH_arm64
+
 
 template <typename A>
 void SectionRelocationsAtom<A>::addSectionReloc(ld::Internal::FinalSection*    sect, ld::Fixup::Kind kind, 
@@ -2321,7 +2027,6 @@ private:
        uint32_t                                                                        symIndexOfLazyPointerAtom(const ld::Atom*);
        uint32_t                                                                        symIndexOfNonLazyPointerAtom(const ld::Atom*);
        uint32_t                                                                        symbolIndex(const ld::Atom*);
-       bool                                                                            kextBundlesDontHaveIndirectSymbolTable();
 
 
        std::vector<uint32_t>                                           _entries;
@@ -2353,9 +2058,11 @@ uint32_t IndirectSymbolTableAtom<A>::symIndexOfStubAtom(const ld::Atom* stubAtom
 {
        for (ld::Fixup::iterator fit = stubAtom->fixupsBegin(); fit != stubAtom->fixupsEnd(); ++fit) {
                if ( fit->binding == ld::Fixup::bindingDirectlyBound ) {
-                       assert((fit->u.target->contentType() == ld::Atom::typeLazyPointer) 
-                                       || (fit->u.target->contentType() == ld::Atom::typeLazyDylibPointer));
-                       return symIndexOfLazyPointerAtom(fit->u.target);
+                       ld::Atom::ContentType type = fit->u.target->contentType();
+                       if (( type == ld::Atom::typeLazyPointer) || (type == ld::Atom::typeLazyDylibPointer) )
+                               return symIndexOfLazyPointerAtom(fit->u.target);
+                       if ( type == ld::Atom::typeNonLazyPointer )
+                               return symIndexOfNonLazyPointerAtom(fit->u.target);
                }
        }
        throw "internal error: stub missing fixup to lazy pointer";
@@ -2393,10 +2100,6 @@ uint32_t IndirectSymbolTableAtom<A>::symIndexOfNonLazyPointerAtom(const ld::Atom
                        default:
                                throw "internal error: unexpected non-lazy pointer binding";
                }
-               // Special case non-lazy-pointer slot used to point to "dyld_stub_binder"
-               // That slot is never bound using indirect symbol table
-               if ( target == _state.compressedFastBinderProxy )
-                       return INDIRECT_SYMBOL_ABS;
                bool targetIsGlobal = (target->scope() == ld::Atom::scopeGlobal);
                switch ( target->definition() ) {
                        case ld::Atom::definitionRegular:
@@ -2475,21 +2178,19 @@ void IndirectSymbolTableAtom<A>::encodeNonLazyPointerSection(ld::Internal::Final
        }
 }
 
-template <typename A>
-bool IndirectSymbolTableAtom<A>::kextBundlesDontHaveIndirectSymbolTable()
-{
-       return true;    
-}
-
 template <typename A>
 void IndirectSymbolTableAtom<A>::encode()
 {
-       // static executables should not have an indirect symbol table
-       if ( this->_options.outputKind() == Options::kStaticExecutable ) 
+       // static executables should not have an indirect symbol table, unless PIE
+       if ( (this->_options.outputKind() == Options::kStaticExecutable) && !_options.positionIndependentExecutable() ) 
+               return;
+
+       // x86_64 kext bundles should not have an indirect symbol table unless using stubs
+       if ( (this->_options.outputKind() == Options::kKextBundle) && !this->_options.kextsUseStubs() )
                return;
 
-       // x86_64 kext bundles should not have an indirect symbol table
-       if ( (this->_options.outputKind() == Options::kKextBundle) && kextBundlesDontHaveIndirectSymbolTable() ) 
+       // slidable static executables (-static -pie) should not have an indirect symbol table
+       if ( (this->_options.outputKind() == Options::kStaticExecutable) && this->_options.positionIndependentExecutable() ) 
                return;
 
        // find all special sections that need a range of the indirect symbol table section